Logo AND Algorithmique Numérique Distribuée

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