#! /usr/bin/env ruby ################################################################# # # generate_experiments3.rb # # Generate a series of assembly functions that each time a different # number of assembly language instructions. The generated functions # are also placed into an array of function pointers so they can be # iterated over. # # Ideally, each function being timed would contain n instructions in a # row. However, when generating a series of such function, there is a # O(n^2) growth in size. In order to keep the code size down, each # function being timed actually calls a "helper function". # # # Users control the specific functions generated by editing the # for loop # # (C) 2016 Zachary Kurmas # ################################################################# $function_count = 0 #***************************************************************** # # Generate the "helper" function # #***************************************************************** def make_step(step, instruction_pool) pool_size = instruction_pool.length asm_statements = (0..step - 1).map do |i| " #{instruction_pool[i % pool_size]}\n" end answer = { :name => "step_group" } answer[:body] = <<-HERE # # #{answer[:name]} # .globl #{answer[:name]} .type #{answer[:name]}, @function #{answer[:name]}: .LFB#{$function_count}: .cfi_startproc #{asm_statements.join} ret .cfi_endproc .LFE#{$function_count}: .size #{answer[:name]}, .-#{answer[:name]} HERE $function_count += 1 answer # return answer end #***************************************************************** # # Generate a C function that will time num_timed instructions. # instruction_pool is an array of instructions that # will be used round-robin. # #***************************************************************** def make_function(num_timed, step, instruction_pool) pool_size = instruction_pool.length asm_statements = (0..num_timed - 1).step(step).map do |i| " call step_group\n" end answer = { :name => "time_#{num_timed}_ops", :num_ops => num_timed } # Insert the function name and __asm__ macros into the C function # (The ~ after the << allows us to indent the body of the multiline string.) answer[:body] = <<-HERE # # #{answer[:name]} # .globl #{answer[:name]} .type #{answer[:name]}, @function #{answer[:name]}: .LFB#{$function_count}: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 pushq %r12 pushq %rbx .cfi_offset 12, -24 .cfi_offset 3, -32 rdtsc push %rax #{asm_statements.join} rdtsc pop %rbx subl %ebx, %eax popq %rbx popq %r12 popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE#{$function_count}: .size #{answer[:name]}, .-#{answer[:name]} HERE $function_count += 1 answer # return answer end #***************************************************************** # # The "main" body of the script # #***************************************************************** # # Generate the first part of the assembly file # puts <