#undef DEBUG_PROFILER #define ALLOCATION_PROFILE #define MODULE_NAMES #define d0 %eax #define d1 %ebx #define a0 %ecx #define a1 %edx #define a2 %ebp #define a3 %esi #define a4 %edi #define sp %esp #if defined(_WINDOWS_) # define align(n) .align (1<<n) #else # define align(n) .align n #endif .global init_profiler .global profile_r .global profile_l .global profile_l2 .global profile_n .global profile_n2 .global profile_s .global profile_s2 .global profile_t .global write_profile_information .global write_profile_stack #ifdef LINUX .global @malloc #else .global @allocate_memory #endif .global __STRING__ .global openF .global closeF .global writeFC .global writeFI .global print_error .global @ab_stack_size .global @ew_print_string .global @ew_print_char .global @create_profile_file_name .global @stack_trace_depth #define next 0 #define time_hi 4 #define time_lo 8 #define n_profiler_calls 12 #define n_strict_calls 16 #define n_lazy_calls 20 #define n_curried_calls 24 #define n_words_allocated 28 #define name 32 #define FunctionProfile 36 .text profile_t: push d0 push a1 rdtsc push a0 mov profile_stack_pointer,a0 push d1 mov -4(a0),d1 sub $4,a0 mov d1,global_last_tail_call mov a0,profile_stack_pointer sub global_time_lo,d0 sbb global_time_hi,a1 add d0,time_lo(d1) adc a1,time_hi(d1) incl n_profiler_calls(d1) #ifdef ALLOCATION_PROFILE mov end_heap,a0 sub a4,a0 mov global_n_bytes_free,d0 add $32,a0 sub a0,d0 mov a0,global_n_bytes_free sar $2,d0 add d0,n_words_allocated(d1) #endif pop d1 pop a0 rdtsc mov a1,global_time_hi pop a1 mov d0,global_time_lo pop d0 ret profile_r: push d0 push a1 rdtsc push a0 mov profile_stack_pointer,a0 push d1 mov -4(a0),d1 sub $4,a0 movl $0,global_last_tail_call mov a0,profile_stack_pointer sub global_time_lo,d0 sbb global_time_hi,a1 add d0,time_lo(d1) adc a1,time_hi(d1) incl n_profiler_calls(d1) #ifdef ALLOCATION_PROFILE mov end_heap,a0 sub a4,a0 mov global_n_bytes_free,d0 add $32,a0 sub a0,d0 mov a0,global_n_bytes_free sar $2,d0 add d0,n_words_allocated(d1) #endif pop d1 pop a0 rdtsc mov a1,global_time_hi pop a1 mov d0,global_time_lo pop d0 ret profile_l: push d0 push a1 rdtsc push d1 mov (a2),d1 test d1,d1 je allocate_function_profile_record_l allocate_function_profile_record_lr: push a0 mov global_last_tail_call,a2 mov profile_stack_pointer,a0 test a2,a2 jne use_tail_calling_function_l mov -4(a0),a2 use_tail_calling_function_lr: #ifdef DEBUG_PROFILER testl (d1),d1 #endif mov d1,(a0) add $4,a0 incl n_curried_calls(d1) jmp profile_n_ allocate_function_profile_record_l: call allocate_function_profile_record jmp allocate_function_profile_record_lr use_tail_calling_function_l: movl $0,global_last_tail_call jmp use_tail_calling_function_lr profile_l2: push d0 push a1 rdtsc push d1 mov (a2),d1 test d1,d1 je allocate_function_profile_record_l2 allocate_function_profile_record_l2r: push a0 mov global_last_tail_call,a2 mov profile_stack_pointer,a0 test a2,a2 jne use_tail_calling_function_l2 mov -4(a0),a2 use_tail_calling_function_l2r: #ifdef DEBUG_PROFILER testl (d1),d1 #endif mov d1,(a0) mov d1,4(a0) add $8,a0 incl n_curried_calls(d1) jmp profile_n_ allocate_function_profile_record_l2: call allocate_function_profile_record jmp allocate_function_profile_record_l2r use_tail_calling_function_l2: movl $0,global_last_tail_call jmp use_tail_calling_function_l2r profile_n: push d0 push a1 rdtsc push d1 mov (a2),d1 test d1,d1 je allocate_function_profile_record_n allocate_function_profile_record_nr: push a0 mov global_last_tail_call,a2 mov profile_stack_pointer,a0 test a2,a2 jne use_tail_calling_function_n mov -4(a0),a2 use_tail_calling_function_nr: #ifdef DEBUG_PROFILER testl (d1),d1 #endif mov d1,(a0) add $4,a0 incl n_lazy_calls(d1) jmp profile_n_ allocate_function_profile_record_n: call allocate_function_profile_record jmp allocate_function_profile_record_nr use_tail_calling_function_n: movl $0,global_last_tail_call jmp use_tail_calling_function_nr profile_n2: push d0 push a1 rdtsc push d1 mov (a2),d1 test d1,d1 je allocate_function_profile_record_n2 allocate_function_profile_record_n2r: push a0 mov global_last_tail_call,a2 mov profile_stack_pointer,a0 test a2,a2 jne use_tail_calling_function_n2 mov -4(a0),a2 use_tail_calling_function_n2r: #ifdef DEBUG_PROFILER testl (d1),d1 #endif mov d1,(a0) mov d1,4(a0) add $8,a0 incl n_lazy_calls(d1) jmp profile_n_ allocate_function_profile_record_n2: call allocate_function_profile_record jmp allocate_function_profile_record_n2r use_tail_calling_function_n2: movl $0,global_last_tail_call jmp use_tail_calling_function_n2r profile_s2: push d0 push a1 rdtsc push d1 mov (a2),d1 test d1,d1 je allocate_function_profile_record_s2 allocate_function_profile_record_s2r: push a0 mov global_last_tail_call,a2 mov profile_stack_pointer,a0 test a2,a2 jne use_tail_calling_function_s2 mov -4(a0),a2 use_tail_calling_function_s2r: #ifdef DEBUG_PROFILER testl (d1),d1 #endif movl d1,(a0) movl d1,4(a0) add $8,a0 jmp profile_s_ allocate_function_profile_record_s2: call allocate_function_profile_record jmp allocate_function_profile_record_s2r use_tail_calling_function_s2: movl $0,global_last_tail_call jmp use_tail_calling_function_s2r profile_s: push d0 push a1 rdtsc push d1 movl (a2),d1 test d1,d1 je allocate_function_profile_record_s allocate_function_profile_record_sr: push a0 mov global_last_tail_call,a2 mov profile_stack_pointer,a0 test a2,a2 jne use_tail_calling_function_s mov -4(a0),a2 use_tail_calling_function_sr: #ifdef DEBUG_PROFILER testl (d1),d1 #endif movl d1,(a0) add $4,a0 profile_s_: incl n_strict_calls(d1) profile_n_: mov a0,profile_stack_pointer sub global_time_lo,d0 sbb global_time_hi,a1 add d0,time_lo(a2) adc a1,time_hi(a2) incl n_profiler_calls(a2) #ifdef ALLOCATION_PROFILE mov end_heap,a0 sub a4,a0 mov global_n_bytes_free,d0 add $32,a0 sub a0,d0 mov a0,global_n_bytes_free sar $2,d0 add d0,n_words_allocated(a2) #endif pop a0 pop d1 rdtsc mov a1,global_time_hi pop a1 mov d0,global_time_lo pop d0 ret allocate_function_profile_record_s: call allocate_function_profile_record jmp allocate_function_profile_record_sr use_tail_calling_function_s: movl $0,global_last_tail_call jmp use_tail_calling_function_sr / argument: a2: function name adress-4 / result: d1: function profile record adress allocate_function_profile_record: push d0 mov global_n_free_records_in_block,d0 mov global_last_allocated_block,d1 test d0,d0 jne no_alloc push d1 push a0 push a1 pushl $128*FunctionProfile #ifdef LINUX call @malloc #else call @allocate_memory #endif add $4,sp test d0,d0 pop a1 pop a0 pop d1 je no_memory mov d0,d1 mov $128,d0 mov d1,global_last_allocated_block no_alloc: dec d0 mov d0,global_n_free_records_in_block lea FunctionProfile(d1),d0 mov d0,global_last_allocated_block xor d0,d0 mov d0,time_hi(d1) mov d0,time_lo(d1) mov d0,n_profiler_calls(d1) mov d0,n_strict_calls(d1) mov d0,n_lazy_calls(d1) mov d0,n_curried_calls(d1) mov d0,n_words_allocated(d1) mov global_profile_records,d0 mov a2,name(d1) mov d0,next(d1) mov d1,global_profile_records mov d1,(a2) pop d0 ret no_memory: movl $not_enough_memory_for_profiler,a2 pop d0 jmp print_error write_profile_information: pushl $profile_file_name call @create_profile_file_name addl $4,sp mov $1,d0 mov $profile_file_name,a0 call openF pop a0 test d1,d1 je cannot_open mov global_profile_records,a2 write_profile_lp: test a2,a2 je end_list mov name(a2),a1 push a2 #ifdef MODULE_NAMES push a1 movl -4(a1),a1 movl (a1),d1 addl $4,a1 write_module_name_lp: subl $1,d1 jc end_module_name pushl d1 movzbl (a1),d1 pushl a1 pushl $l0 pushl a0 jmp writeFC l0: popl a1 movl d0,a0 movl d1,d0 popl d1 addl $1,a1 jmp write_module_name_lp end_module_name: mov $' ',d1 push $l00 push a0 jmp writeFC l00: mov d0,a0 mov d1,d0 pop a1 #endif add $3,a1 write_function_name_lp: movzbl 1(a1),d1 add $1,a1 test d1,d1 je end_function_name push a1 push $l1 push a0 jmp writeFC l1: mov d0,a0 mov d1,d0 pop a1 jmp write_function_name_lp end_function_name: mov $' ',d1 push $l2 push a0 jmp writeFC l2: mov d0,a0 mov d1,d0 mov (sp),d1 mov n_strict_calls(d1),d1 call writeFI_space mov (sp),d1 mov n_lazy_calls(d1),d1 call writeFI_space mov (sp),d1 mov n_curried_calls(d1),d1 call writeFI_space mov (sp),d1 mov n_profiler_calls(d1),d1 call writeFI_space mov (sp),d1 mov n_words_allocated(d1),d1 call writeFI_space mov (sp),d1 mov time_hi(d1),d1 call writeFI_space mov (sp),d1 mov time_lo(d1),d1 pushl $l3 push a0 jmp writeFI l3: mov d0,a0 mov d1,d0 mov $10,d1 pushl $l4 push a0 jmp writeFC l4: mov d0,a0 mov d1,d0 pop a2 mov next(a2),a2 jmp write_profile_lp writeFI_space: pushl $l5 push a0 jmp writeFI l5: mov d0,a0 mov d1,d0 push $l6 push a0 mov $' ',d1 jmp writeFC l6: mov d0,a0 mov d1,d0 ret end_list: mov d0,d1 call closeF cannot_open: ret write_profile_stack: mov profile_stack_pointer,d0 test d0,d0 je stack_not_initialised push d0 push $stack_trace_string call @ew_print_string add $4,sp pop d0 / mov $12,a2 movl @stack_trace_depth,a2 write_functions_on_stack: mov -4(d0),d1 sub $4,d0 test d1,d1 je end_profile_stack push d0 mov name(d1),a0 push a2 #ifdef MODULE_NAMES movl -4(a0),a1 #endif add $4,a0 #ifdef MODULE_NAMES pushl (a1) addl $4,a1 pushl a1 #endif pushl a0 call @ew_print_string add $4,sp #ifdef MODULE_NAMES pushl $module_string call @ew_print_string add $4,sp call @ew_print_text addl $8,sp pushl $']' call @ew_print_char add $4,sp #endif pushl $10 call @ew_print_char add $4,sp pop a2 pop d0 sub $1,a2 jne write_functions_on_stack end_profile_stack: stack_not_initialised: ret init_profiler: pushfl movl $0x200000,%eax pop %ebx xor %ebx,%eax push %eax popfl pushfl pop %eax xor %ebx,%eax jz no_tsc_error movl $1,%eax cpuid andl $16,%edx jz no_tsc_error pushl @ab_stack_size #ifdef LINUX call @malloc #else call @allocate_memory #endif add $4,sp test d0,d0 je init_profiler_error push d0 mov $start_string,a2 call allocate_function_profile_record pop a1 mov d1,4(a1) movl $0,(a1) add $8,a1 mov a1,profile_stack_pointer movl $0,global_last_tail_call mov end_heap,a1 sub a4,a1 add $32,a1 mov a1,global_n_bytes_free rdtsc mov a1,global_time_hi mov d0,global_time_lo ret no_tsc_error: movl $0,profile_stack_pointer movl $no_tsc_error_string,a2 jmp print_error init_profiler_error: movl $0,profile_stack_pointer movl $not_enough_memory_for_profile_stack,a2 jmp print_error .data align (2) global_n_free_records_in_block: .long 0 / 0 n free records in block global_last_allocated_block: .long 0 / 4 latest allocated block global_profile_records: .long 0 / 8 profile record list global_time_hi: .long 0 / 12 clock global_time_lo: .long 0 global_last_tail_call: .long 0 / last tail calling function global_n_bytes_free: .long 0 profile_file_name: .long __STRING__+2 .long 0 .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .long 0 @stack_trace_depth: .long 12 align (2) #ifdef MODULE_NAMES # if 0 / m_system also defined in istartup.s m_system: .long 6 .ascii "System" .byte 0 .byte 0 # endif .long m_system #endif start_string: .long 0 .asciz "start" align (2) no_tsc_error_string: .ascii "cannot profile because this processor does not have a time stamp counter" .byte 10 .byte 0 not_enough_memory_for_profile_stack: .ascii "not enough memory for profile stack" .byte 10 .byte 0 not_enough_memory_for_profiler: .ascii "not enough memory for profiler" .byte 10 .byte 0 stack_trace_string: .ascii "Stack trace:" .byte 10 .byte 0 #ifdef MODULE_NAMES module_string: .asciz " [module: " #endif align (2)