Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of git+ssh://scm.gforge.inria.fr//gitroot/simgrid/simgrid
[simgrid.git] / src / mc / mc_ignore.c
1 /* Copyright (c) 2008-2014. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include "internal_config.h"
8 #include "mc_private.h"
9 #include "smpi/private.h"
10
11 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_ignore, mc,
12                                 "Logging specific to MC ignore mechanism");
13
14
15 /**************************** Global variables ******************************/
16 xbt_dynar_t mc_checkpoint_ignore;
17 extern xbt_dynar_t mc_heap_comparison_ignore;
18 extern xbt_dynar_t stacks_areas;
19
20 /**************************** Structures ******************************/
21 typedef struct s_mc_stack_ignore_variable {
22   char *var_name;
23   char *frame;
24 } s_mc_stack_ignore_variable_t, *mc_stack_ignore_variable_t;
25
26 /**************************** Free functions ******************************/
27
28 static void stack_ignore_variable_free(mc_stack_ignore_variable_t v)
29 {
30   xbt_free(v->var_name);
31   xbt_free(v->frame);
32   xbt_free(v);
33 }
34
35 static void stack_ignore_variable_free_voidp(void *v)
36 {
37   stack_ignore_variable_free((mc_stack_ignore_variable_t) * (void **) v);
38 }
39
40 void heap_ignore_region_free(mc_heap_ignore_region_t r)
41 {
42   xbt_free(r);
43 }
44
45 void heap_ignore_region_free_voidp(void *r)
46 {
47   heap_ignore_region_free((mc_heap_ignore_region_t) * (void **) r);
48 }
49
50 static void checkpoint_ignore_region_free(mc_checkpoint_ignore_region_t r)
51 {
52   xbt_free(r);
53 }
54
55 static void checkpoint_ignore_region_free_voidp(void *r)
56 {
57   checkpoint_ignore_region_free((mc_checkpoint_ignore_region_t) * (void **) r);
58 }
59
60 /***********************************************************************/
61
62 void MC_ignore_heap(void *address, size_t size)
63 {
64
65   int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
66
67   MC_SET_MC_HEAP;
68
69   mc_heap_ignore_region_t region = NULL;
70   region = xbt_new0(s_mc_heap_ignore_region_t, 1);
71   region->address = address;
72   region->size = size;
73
74   region->block =
75       ((char *) address -
76        (char *) ((xbt_mheap_t) std_heap)->heapbase) / BLOCKSIZE + 1;
77
78   if (((xbt_mheap_t) std_heap)->heapinfo[region->block].type == 0) {
79     region->fragment = -1;
80     ((xbt_mheap_t) std_heap)->heapinfo[region->block].busy_block.ignore++;
81   } else {
82     region->fragment =
83         ((uintptr_t) (ADDR2UINT(address) % (BLOCKSIZE))) >> ((xbt_mheap_t)
84                                                              std_heap)->
85         heapinfo[region->block].type;
86     ((xbt_mheap_t) std_heap)->heapinfo[region->block].busy_frag.ignore[region->
87                                                                        fragment]++;
88   }
89
90   if (mc_heap_comparison_ignore == NULL) {
91     mc_heap_comparison_ignore =
92         xbt_dynar_new(sizeof(mc_heap_ignore_region_t),
93                       heap_ignore_region_free_voidp);
94     xbt_dynar_push(mc_heap_comparison_ignore, &region);
95     if (!raw_mem_set)
96       MC_SET_STD_HEAP;
97     return;
98   }
99
100   unsigned int cursor = 0;
101   mc_heap_ignore_region_t current_region = NULL;
102   int start = 0;
103   int end = xbt_dynar_length(mc_heap_comparison_ignore) - 1;
104
105   while (start <= end) {
106     cursor = (start + end) / 2;
107     current_region =
108         (mc_heap_ignore_region_t) xbt_dynar_get_as(mc_heap_comparison_ignore,
109                                                    cursor,
110                                                    mc_heap_ignore_region_t);
111     if (current_region->address == address) {
112       heap_ignore_region_free(region);
113       if (!raw_mem_set)
114         MC_SET_STD_HEAP;
115       return;
116     } else if (current_region->address < address) {
117       start = cursor + 1;
118     } else {
119       end = cursor - 1;
120     }
121   }
122
123   if (current_region->address < address)
124     xbt_dynar_insert_at(mc_heap_comparison_ignore, cursor + 1, &region);
125   else
126     xbt_dynar_insert_at(mc_heap_comparison_ignore, cursor, &region);
127
128   if (!raw_mem_set)
129     MC_SET_STD_HEAP;
130 }
131
132 void MC_remove_ignore_heap(void *address, size_t size)
133 {
134
135   int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
136
137   MC_SET_MC_HEAP;
138
139   unsigned int cursor = 0;
140   int start = 0;
141   int end = xbt_dynar_length(mc_heap_comparison_ignore) - 1;
142   mc_heap_ignore_region_t region;
143   int ignore_found = 0;
144
145   while (start <= end) {
146     cursor = (start + end) / 2;
147     region =
148         (mc_heap_ignore_region_t) xbt_dynar_get_as(mc_heap_comparison_ignore,
149                                                    cursor,
150                                                    mc_heap_ignore_region_t);
151     if (region->address == address) {
152       ignore_found = 1;
153       break;
154     } else if (region->address < address) {
155       start = cursor + 1;
156     } else {
157       if ((char *) region->address <= ((char *) address + size)) {
158         ignore_found = 1;
159         break;
160       } else {
161         end = cursor - 1;
162       }
163     }
164   }
165
166   if (ignore_found == 1) {
167     xbt_dynar_remove_at(mc_heap_comparison_ignore, cursor, NULL);
168     MC_remove_ignore_heap(address, size);
169   }
170
171   if (!raw_mem_set)
172     MC_SET_STD_HEAP;
173
174 }
175
176 void MC_ignore_global_variable(const char *name)
177 {
178
179   int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
180
181   MC_SET_MC_HEAP;
182
183   xbt_assert(mc_libsimgrid_info, "MC subsystem not initialized");
184
185   unsigned int cursor = 0;
186   dw_variable_t current_var;
187   int start = 0;
188   int end = xbt_dynar_length(mc_libsimgrid_info->global_variables) - 1;
189
190   while (start <= end) {
191     cursor = (start + end) / 2;
192     current_var =
193         (dw_variable_t) xbt_dynar_get_as(mc_libsimgrid_info->global_variables,
194                                          cursor, dw_variable_t);
195     if (strcmp(current_var->name, name) == 0) {
196       xbt_dynar_remove_at(mc_libsimgrid_info->global_variables, cursor, NULL);
197       start = 0;
198       end = xbt_dynar_length(mc_libsimgrid_info->global_variables) - 1;
199     } else if (strcmp(current_var->name, name) < 0) {
200       start = cursor + 1;
201     } else {
202       end = cursor - 1;
203     }
204   }
205
206   if (!raw_mem_set)
207     MC_SET_STD_HEAP;
208 }
209
210 /** \brief Ignore a local variable in a scope
211  *
212  *  Ignore all instances of variables with a given name in
213  *  any (possibly inlined) subprogram with a given namespaced
214  *  name.
215  *
216  *  \param var_name        Name of the local variable (or parameter to ignore)
217  *  \param subprogram_name Name of the subprogram fo ignore (NULL for any)
218  *  \param subprogram      (possibly inlined) Subprogram of the scope
219  *  \param scope           Current scope
220  */
221 static void mc_ignore_local_variable_in_scope(const char *var_name,
222                                               const char *subprogram_name,
223                                               dw_frame_t subprogram,
224                                               dw_frame_t scope)
225 {
226   // Processing of direct variables:
227
228   // If the current subprogram matche the given name:
229   if (subprogram_name == NULL || strcmp(subprogram_name, subprogram->name) == 0) {
230
231     // Try to find the variable and remove it:
232     int start = 0;
233     int end = xbt_dynar_length(scope->variables) - 1;
234
235     // Dichotomic search:
236     while (start <= end) {
237       int cursor = (start + end) / 2;
238       dw_variable_t current_var =
239           (dw_variable_t) xbt_dynar_get_as(scope->variables, cursor,
240                                            dw_variable_t);
241
242       int compare = strcmp(current_var->name, var_name);
243       if (compare == 0) {
244         // Variable found, remove it:
245         xbt_dynar_remove_at(scope->variables, cursor, NULL);
246
247         // and start again:
248         start = 0;
249         end = xbt_dynar_length(scope->variables) - 1;
250       } else if (compare < 0) {
251         start = cursor + 1;
252       } else {
253         end = cursor - 1;
254       }
255     }
256
257   }
258   // And recursive processing in nested scopes:
259   unsigned cursor = 0;
260   dw_frame_t nested_scope = NULL;
261   xbt_dynar_foreach(scope->scopes, cursor, nested_scope) {
262     // The new scope may be an inlined subroutine, in this case we want to use its
263     // namespaced name in recursive calls:
264     dw_frame_t nested_subprogram =
265         nested_scope->tag ==
266         DW_TAG_inlined_subroutine ? nested_scope : subprogram;
267
268     mc_ignore_local_variable_in_scope(var_name, subprogram_name,
269                                       nested_subprogram, nested_scope);
270   }
271 }
272
273 static void MC_ignore_local_variable_in_object(const char *var_name,
274                                                const char *subprogram_name,
275                                                mc_object_info_t info)
276 {
277   xbt_dict_cursor_t cursor2;
278   dw_frame_t frame;
279   char *key;
280   xbt_dict_foreach(info->subprograms, cursor2, key, frame) {
281     mc_ignore_local_variable_in_scope(var_name, subprogram_name, frame, frame);
282   }
283 }
284
285 void MC_ignore_local_variable(const char *var_name, const char *frame_name)
286 {
287
288   int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
289
290   if (strcmp(frame_name, "*") == 0)
291     frame_name = NULL;
292
293   MC_SET_MC_HEAP;
294
295   MC_ignore_local_variable_in_object(var_name, frame_name, mc_libsimgrid_info);
296   if (frame_name != NULL)
297     MC_ignore_local_variable_in_object(var_name, frame_name, mc_binary_info);
298
299   if (!raw_mem_set)
300     MC_SET_STD_HEAP;
301
302 }
303
304 /** @brief Register a stack in the model checker
305  *
306  *  The stacks are allocated in the heap. The MC handle them especially
307  *  when we analyse/compare the content of theap so it must be told where
308  *  they are with this function.
309  *
310  *  @param stack
311  *  @param process Process owning the stack
312  *  @param context
313  *  @param size    Size of the stack
314  */
315 void MC_new_stack_area(void *stack, smx_process_t process, void *context, size_t size)
316 {
317
318   int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
319
320   MC_SET_MC_HEAP;
321
322   if (stacks_areas == NULL)
323     stacks_areas = xbt_dynar_new(sizeof(stack_region_t), NULL);
324
325   stack_region_t region = NULL;
326   region = xbt_new0(s_stack_region_t, 1);
327   region->address = stack;
328   region->process_name = process && process->name ? strdup(process->name) : NULL;
329   region->context = context;
330   region->size = size;
331   region->block =
332       ((char *) stack -
333        (char *) ((xbt_mheap_t) std_heap)->heapbase) / BLOCKSIZE + 1;
334 #ifdef HAVE_SMPI
335   if (smpi_privatize_global_variables && process) {
336     region->process_index = smpi_process_index_of_smx_process(process);
337   } else
338 #endif
339   region->process_index = -1;
340
341   xbt_dynar_push(stacks_areas, &region);
342
343   if (!raw_mem_set)
344     MC_SET_STD_HEAP;
345 }
346
347 void MC_ignore(void *addr, size_t size)
348 {
349
350   int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
351
352   MC_SET_MC_HEAP;
353
354   if (mc_checkpoint_ignore == NULL)
355     mc_checkpoint_ignore =
356         xbt_dynar_new(sizeof(mc_checkpoint_ignore_region_t),
357                       checkpoint_ignore_region_free_voidp);
358
359   mc_checkpoint_ignore_region_t region =
360       xbt_new0(s_mc_checkpoint_ignore_region_t, 1);
361   region->addr = addr;
362   region->size = size;
363
364   if (xbt_dynar_is_empty(mc_checkpoint_ignore)) {
365     xbt_dynar_push(mc_checkpoint_ignore, &region);
366   } else {
367
368     unsigned int cursor = 0;
369     int start = 0;
370     int end = xbt_dynar_length(mc_checkpoint_ignore) - 1;
371     mc_checkpoint_ignore_region_t current_region = NULL;
372
373     while (start <= end) {
374       cursor = (start + end) / 2;
375       current_region =
376           (mc_checkpoint_ignore_region_t) xbt_dynar_get_as(mc_checkpoint_ignore,
377                                                            cursor,
378                                                            mc_checkpoint_ignore_region_t);
379       if (current_region->addr == addr) {
380         if (current_region->size == size) {
381           checkpoint_ignore_region_free(region);
382           if (!raw_mem_set)
383             MC_SET_STD_HEAP;
384           return;
385         } else if (current_region->size < size) {
386           start = cursor + 1;
387         } else {
388           end = cursor - 1;
389         }
390       } else if (current_region->addr < addr) {
391         start = cursor + 1;
392       } else {
393         end = cursor - 1;
394       }
395     }
396
397     if (current_region->addr == addr) {
398       if (current_region->size < size) {
399         xbt_dynar_insert_at(mc_checkpoint_ignore, cursor + 1, &region);
400       } else {
401         xbt_dynar_insert_at(mc_checkpoint_ignore, cursor, &region);
402       }
403     } else if (current_region->addr < addr) {
404       xbt_dynar_insert_at(mc_checkpoint_ignore, cursor + 1, &region);
405     } else {
406       xbt_dynar_insert_at(mc_checkpoint_ignore, cursor, &region);
407     }
408   }
409
410   if (!raw_mem_set)
411     MC_SET_STD_HEAP;
412 }