Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Multiple .so support in MC_ignore_local_variable()
[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 void MC_ignore_heap(void *address, size_t size)
65 {
66
67   int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
68
69   MC_SET_MC_HEAP;
70
71   mc_heap_ignore_region_t region = NULL;
72   region = xbt_new0(s_mc_heap_ignore_region_t, 1);
73   region->address = address;
74   region->size = size;
75
76   region->block =
77       ((char *) address -
78        (char *) std_heap->heapbase) / BLOCKSIZE + 1;
79
80   if (std_heap->heapinfo[region->block].type == 0) {
81     region->fragment = -1;
82     std_heap->heapinfo[region->block].busy_block.ignore++;
83   } else {
84     region->fragment =
85         ((uintptr_t) (ADDR2UINT(address) % (BLOCKSIZE))) >> std_heap->
86         heapinfo[region->block].type;
87     std_heap->heapinfo[region->block].busy_frag.ignore[region->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   mc_process_t process = &mc_model_checker->process;
179   int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
180
181   MC_SET_MC_HEAP;
182
183   xbt_assert(process->object_infos, "MC subsystem not initialized");
184
185   size_t n = process->object_infos_size;
186   for (size_t i=0; i!=n; ++i) {
187     mc_object_info_t info = process->object_infos[i];
188
189     // Binary search:
190     int start = 0;
191     int end = xbt_dynar_length(info->global_variables) - 1;
192     while (start <= end) {
193       unsigned int cursor = (start + end) / 2;
194       dw_variable_t current_var =
195           (dw_variable_t) xbt_dynar_get_as(info->global_variables,
196                                            cursor, dw_variable_t);
197       if (strcmp(current_var->name, name) == 0) {
198         xbt_dynar_remove_at(info->global_variables, cursor, NULL);
199         start = 0;
200         end = xbt_dynar_length(info->global_variables) - 1;
201       } else if (strcmp(current_var->name, name) < 0) {
202         start = cursor + 1;
203       } else {
204         end = cursor - 1;
205       }
206     }
207   }
208
209   if (!raw_mem_set)
210     MC_SET_STD_HEAP;
211 }
212
213 /** \brief Ignore a local variable in a scope
214  *
215  *  Ignore all instances of variables with a given name in
216  *  any (possibly inlined) subprogram with a given namespaced
217  *  name.
218  *
219  *  \param var_name        Name of the local variable (or parameter to ignore)
220  *  \param subprogram_name Name of the subprogram fo ignore (NULL for any)
221  *  \param subprogram      (possibly inlined) Subprogram of the scope
222  *  \param scope           Current scope
223  */
224 static void mc_ignore_local_variable_in_scope(const char *var_name,
225                                               const char *subprogram_name,
226                                               dw_frame_t subprogram,
227                                               dw_frame_t scope)
228 {
229   // Processing of direct variables:
230
231   // If the current subprogram matche the given name:
232   if (!subprogram_name ||
233       (subprogram->name && strcmp(subprogram_name, subprogram->name) == 0)) {
234
235     // Try to find the variable and remove it:
236     int start = 0;
237     int end = xbt_dynar_length(scope->variables) - 1;
238
239     // Dichotomic search:
240     while (start <= end) {
241       int cursor = (start + end) / 2;
242       dw_variable_t current_var =
243           (dw_variable_t) xbt_dynar_get_as(scope->variables, cursor,
244                                            dw_variable_t);
245
246       int compare = strcmp(current_var->name, var_name);
247       if (compare == 0) {
248         // Variable found, remove it:
249         xbt_dynar_remove_at(scope->variables, cursor, NULL);
250
251         // and start again:
252         start = 0;
253         end = xbt_dynar_length(scope->variables) - 1;
254       } else if (compare < 0) {
255         start = cursor + 1;
256       } else {
257         end = cursor - 1;
258       }
259     }
260
261   }
262   // And recursive processing in nested scopes:
263   unsigned cursor = 0;
264   dw_frame_t nested_scope = NULL;
265   xbt_dynar_foreach(scope->scopes, cursor, nested_scope) {
266     // The new scope may be an inlined subroutine, in this case we want to use its
267     // namespaced name in recursive calls:
268     dw_frame_t nested_subprogram =
269         nested_scope->tag ==
270         DW_TAG_inlined_subroutine ? nested_scope : subprogram;
271
272     mc_ignore_local_variable_in_scope(var_name, subprogram_name,
273                                       nested_subprogram, nested_scope);
274   }
275 }
276
277 static void MC_ignore_local_variable_in_object(const char *var_name,
278                                                const char *subprogram_name,
279                                                mc_object_info_t info)
280 {
281   xbt_dict_cursor_t cursor2;
282   dw_frame_t frame;
283   char *key;
284   xbt_dict_foreach(info->subprograms, cursor2, key, frame) {
285     mc_ignore_local_variable_in_scope(var_name, subprogram_name, frame, frame);
286   }
287 }
288
289 void MC_ignore_local_variable(const char *var_name, const char *frame_name)
290 {
291   mc_process_t process = &mc_model_checker->process;
292
293
294   int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
295
296   if (strcmp(frame_name, "*") == 0)
297     frame_name = NULL;
298
299   MC_SET_MC_HEAP;
300
301   size_t n = process->object_infos_size;
302   size_t i;
303   for (i=0; i!=n; ++i) {
304     MC_ignore_local_variable_in_object(var_name, frame_name, process->object_infos[i]);
305   }
306
307   if (!raw_mem_set)
308     MC_SET_STD_HEAP;
309
310 }
311
312 /** @brief Register a stack in the model checker
313  *
314  *  The stacks are allocated in the heap. The MC handle them especially
315  *  when we analyse/compare the content of theap so it must be told where
316  *  they are with this function.
317  *
318  *  @param stack
319  *  @param process Process owning the stack
320  *  @param context
321  *  @param size    Size of the stack
322  */
323 void MC_new_stack_area(void *stack, smx_process_t process, void *context, size_t size)
324 {
325
326   int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
327
328   MC_SET_MC_HEAP;
329
330   if (stacks_areas == NULL)
331     stacks_areas = xbt_dynar_new(sizeof(stack_region_t), NULL);
332
333   stack_region_t region = NULL;
334   region = xbt_new0(s_stack_region_t, 1);
335   region->address = stack;
336   region->process_name = process && process->name ? strdup(process->name) : NULL;
337   region->context = context;
338   region->size = size;
339   region->block =
340       ((char *) stack -
341        (char *) std_heap->heapbase) / BLOCKSIZE + 1;
342 #ifdef HAVE_SMPI
343   if (smpi_privatize_global_variables && process) {
344     region->process_index = smpi_process_index_of_smx_process(process);
345   } else
346 #endif
347   region->process_index = -1;
348
349   xbt_dynar_push(stacks_areas, &region);
350
351   if (!raw_mem_set)
352     MC_SET_STD_HEAP;
353 }
354
355 void MC_ignore(void *addr, size_t size)
356 {
357
358   int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
359
360   MC_SET_MC_HEAP;
361
362   if (mc_checkpoint_ignore == NULL)
363     mc_checkpoint_ignore =
364         xbt_dynar_new(sizeof(mc_checkpoint_ignore_region_t),
365                       checkpoint_ignore_region_free_voidp);
366
367   mc_checkpoint_ignore_region_t region =
368       xbt_new0(s_mc_checkpoint_ignore_region_t, 1);
369   region->addr = addr;
370   region->size = size;
371
372   if (xbt_dynar_is_empty(mc_checkpoint_ignore)) {
373     xbt_dynar_push(mc_checkpoint_ignore, &region);
374   } else {
375
376     unsigned int cursor = 0;
377     int start = 0;
378     int end = xbt_dynar_length(mc_checkpoint_ignore) - 1;
379     mc_checkpoint_ignore_region_t current_region = NULL;
380
381     while (start <= end) {
382       cursor = (start + end) / 2;
383       current_region =
384           (mc_checkpoint_ignore_region_t) xbt_dynar_get_as(mc_checkpoint_ignore,
385                                                            cursor,
386                                                            mc_checkpoint_ignore_region_t);
387       if (current_region->addr == addr) {
388         if (current_region->size == size) {
389           checkpoint_ignore_region_free(region);
390           if (!raw_mem_set)
391             MC_SET_STD_HEAP;
392           return;
393         } else if (current_region->size < size) {
394           start = cursor + 1;
395         } else {
396           end = cursor - 1;
397         }
398       } else if (current_region->addr < addr) {
399         start = cursor + 1;
400       } else {
401         end = cursor - 1;
402       }
403     }
404
405     if (current_region->addr == addr) {
406       if (current_region->size < size) {
407         xbt_dynar_insert_at(mc_checkpoint_ignore, cursor + 1, &region);
408       } else {
409         xbt_dynar_insert_at(mc_checkpoint_ignore, cursor, &region);
410       }
411     } else if (current_region->addr < addr) {
412       xbt_dynar_insert_at(mc_checkpoint_ignore, cursor + 1, &region);
413     } else {
414       xbt_dynar_insert_at(mc_checkpoint_ignore, cursor, &region);
415     }
416   }
417
418   if (!raw_mem_set)
419     MC_SET_STD_HEAP;
420 }