Advertisement
Guest User

gcc plugin to register new __attribute__

a guest
Jul 26th, 2014
211
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.73 KB | None | 0 0
  1. Imagine that we have some Clang structs with alot of fields and we want to (this is cited from a TODO in a
  2. linux kernel module):
  3.  
  4. "Put the most frequently accessed fields at the beginning of structures to maximize cache efficiency."
  5.  
  6. Consider this example program:
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10.  
  11. struct car {
  12. char name[16];
  13. float km_h;
  14. float fuel_efficiency;
  15. float price;
  16. };
  17.  
  18. struct car_grading {
  19. float km_h_multiplier;
  20. float fuel_efficiency_multiplier;
  21. float price_multiplier;
  22. float maximum_price;
  23. };
  24.  
  25. struct car_grading *g;
  26.  
  27. static int grading_function(struct car *a)
  28. {
  29. return (int) (a->km_h * g->km_h_multiplier +
  30. a->fuel_efficiency * g->fuel_efficiency_multiplier +
  31. (a->price - g->maximum_price) * g->price_multiplier);
  32. }
  33.  
  34. int compare_cars(const void *hi, const void *lo)
  35. {
  36. struct car *__hi = (struct car *) hi;
  37. struct car *__lo = (struct car *) lo;
  38.  
  39. if(__lo->price > g->maximum_price)
  40. return 1;
  41. if(__hi->price > g->maximum_price)
  42. return -1;
  43.  
  44. return (grading_function(__hi) - grading_function(__lo));
  45. }
  46.  
  47. int main(void)
  48. {
  49. struct car cars[] = {
  50. {"Ferrari", 200.f, 30.f, 50000.f},
  51. {"Opel", 150.f, 20.f, 15000.f},
  52. {"Citroen", 100.f, 25.f, 11000.f},
  53. { }
  54. };
  55.  
  56. g = malloc(sizeof(struct car_grading));
  57. g->km_h_multiplier = 1.f;
  58. g->fuel_efficiency_multiplier = 3.f;
  59. g->price_multiplier = 2.f;
  60. g->maximum_price = 23000.f;
  61.  
  62. qsort((void *) cars, 3, sizeof(struct car), compare_cars);
  63. printf("gonna buy this car: %s\n", cars[2].name);
  64.  
  65. return 0;
  66. }
  67.  
  68. The lesson learned from this program: char 'name' [8] is the *first* field in
  69. struct 'car' but it's used only *once*.
  70.  
  71. The fields 'km_h' and 'fuel_efficiency' are used the same amount, but 'price' is used
  72. *more*, but it's the *last* field!
  73.  
  74. It would be better to organise struct 'car' like this:
  75.  
  76. struct car {
  77. float price;
  78. float km_h;
  79. float fuel_efficiency;
  80. char name[16];
  81. };
  82.  
  83. In struct 'car_grading', the field 'maximum_price' should be put at the top, like this:
  84.  
  85. struct car_grading {
  86. float maximum_price;
  87. float km_h_multiplier;
  88. float fuel_efficiency_multiplier;
  89. float price_multiplier;
  90. };
  91.  
  92. It is easy to predict the behaviour of a simple program. Larger programs,
  93. with more and less frequently used functions, complex control flows, and larger structures, could benefit from counting
  94. the usage of every field in important and large structures.
  95.  
  96. A way to do that would be to "inject" into the program:
  97.  
  98. 1. a special table in a new assembly .section, called ".debug_field_frequency",
  99. 2. code, that updates some counter in that table before some field of some structure is used.
  100.  
  101. Obviously, the code will only be "injected" into functions, static to the main compilation unit.
  102. I used the library qsort() in my program, because it doesn't really do anything with the structure fields, it works on
  103. structure pointers and throws them to compare_and_maybe_swap_cars().
  104.  
  105. The definition of field usage:
  106.  
  107. 1. assigning values,
  108. 2. checking values and using values,
  109. 3. sending values to another function (that could be under using values).
  110.  
  111. Basicly, everything that would do mov %some_register, -location_of_field(%stack_pointer).
  112.  
  113. Our parsers algorithm:
  114.  
  115. Global vars:
  116.  
  117. Let num_structures be 0
  118. Let field_frequency_table_size be 0
  119. Initialize circular linked list struct_to_ID
  120.  
  121. (this should be in the callback, that's triggered for every struct that has __attribute__ ((field_frequency))
  122.  
  123. Print "structure with ID $num_structures is" name_of_structure(this_structure)
  124. Insert new node with values #name_of_structure, and field_frequency_table_size to struct_to_ID
  125. Increment num_structures
  126. Add number_of_fields(this_structure) to field_frequency_table_size
  127.  
  128. (this should be in the callback that's triggered in every function)
  129.  
  130. For every function
  131. Check in FnDecl.Args it accepts pointers to atleast one of the tracked structures and store that in bool accepts_pointers
  132. Check in Fndecl.Body.Decl if it initialises any tracked structures' fields.
  133. If not And If accepts_pointers is false
  134. Break
  135. For every field usage (see our definition of field usage)
  136. find the appropriate structure in the struct_to_ID linked list
  137. Let tmp be offsetof(this_structure) (we get that from the node) + offsetof(used_field, this_structure)
  138. write "asm ("mov -tmp(stack location of field_frequency_table, %eax");"
  139. "asm ("add %eax, 1");"
  140. "asm ("mov -tmp(stack location of field_frequency_table, %eax");"
  141.  
  142.  
  143. (also need to write to main.Body.Decl)
  144.  
  145. Write ("unsigned long field_frequency_table[field_frequency] __attribute__ ((section ".debug_field_frequency")) = { };")
  146.  
  147. What I am asking is: is there a way to do it without using custom attributes, and if now, how to start?
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement