xref: /petsc/src/sys/logging/state/logregistry.c (revision 66af8762ec03dbef0e079729eb2a1734a35ed7ff)
1 #include <petsc/private/logimpl.h> /*I "petsclog.h" I*/
2 
3 #define PETSC_LOG_RESIZABLE_ARRAY_HAS_NAME(Container, Entry, Key, Equal) \
4   static inline PETSC_UNUSED PetscErrorCode PetscLog##Container##Destructor(Entry *entry) \
5   { \
6     PetscFunctionBegin; \
7     PetscCall(PetscFree(entry->name)); \
8     PetscFunctionReturn(PETSC_SUCCESS); \
9   } \
10   PETSC_LOG_RESIZABLE_ARRAY(Container, Entry, Key, NULL, PetscLog##Container##Destructor, Equal)
11 
12 #define PETSC_LOG_RESIZABLE_ARRAY_KEY_BY_NAME(Container, Entry) \
13   static inline PETSC_UNUSED PetscErrorCode PetscLog##Container##Equal(Entry *entry, const char *name, PetscBool *is_equal) \
14   { \
15     PetscFunctionBegin; \
16     PetscCall(PetscStrcmp(entry->name, name, is_equal)); \
17     PetscFunctionReturn(PETSC_SUCCESS); \
18   } \
19   PETSC_LOG_RESIZABLE_ARRAY_HAS_NAME(Container, Entry, const char *, PetscLog##Container##Equal)
20 
21 static PetscErrorCode PetscLogClassArrayEqual(PetscLogClassInfo *class_info, PetscLogClassInfo *key, PetscBool *is_equal)
22 {
23   PetscFunctionBegin;
24   if (key->name) {
25     PetscCall(PetscStrcmp(class_info->name, key->name, is_equal));
26   } else {
27     *is_equal = (class_info->classid == key->classid) ? PETSC_TRUE : PETSC_FALSE;
28   }
29   PetscFunctionReturn(PETSC_SUCCESS);
30 }
31 
32 PETSC_LOG_RESIZABLE_ARRAY_KEY_BY_NAME(EventArray, PetscLogEventInfo)
33 PETSC_LOG_RESIZABLE_ARRAY_KEY_BY_NAME(StageArray, PetscLogStageInfo)
34 PETSC_LOG_RESIZABLE_ARRAY_HAS_NAME(ClassArray, PetscLogClassInfo, PetscLogClassInfo *, PetscLogClassArrayEqual)
35 
36 struct _n_PetscLogRegistry {
37   PetscLogEventArray events;
38   PetscLogClassArray classes;
39   PetscLogStageArray stages;
40 };
41 
42 PETSC_INTERN PetscErrorCode PetscLogRegistryCreate(PetscLogRegistry *registry_p)
43 {
44   PetscLogRegistry registry;
45 
46   PetscFunctionBegin;
47   PetscCall(PetscNew(registry_p));
48   registry = *registry_p;
49   PetscCall(PetscLogEventArrayCreate(128, &registry->events));
50   PetscCall(PetscLogStageArrayCreate(8, &registry->stages));
51   PetscCall(PetscLogClassArrayCreate(128, &registry->classes));
52   PetscFunctionReturn(PETSC_SUCCESS);
53 }
54 
55 PETSC_INTERN PetscErrorCode PetscLogRegistryDestroy(PetscLogRegistry registry)
56 {
57   PetscFunctionBegin;
58   PetscCall(PetscLogEventArrayDestroy(&registry->events));
59   PetscCall(PetscLogClassArrayDestroy(&registry->classes));
60   PetscCall(PetscLogStageArrayDestroy(&registry->stages));
61   PetscCall(PetscFree(registry));
62   PetscFunctionReturn(PETSC_SUCCESS);
63 }
64 
65 PETSC_INTERN PetscErrorCode PetscLogRegistryGetNumEvents(PetscLogRegistry registry, PetscInt *num_events, PetscInt *max_events)
66 {
67   PetscFunctionBegin;
68   PetscCall(PetscLogEventArrayGetSize(registry->events, num_events, max_events));
69   PetscFunctionReturn(PETSC_SUCCESS);
70 }
71 
72 PETSC_INTERN PetscErrorCode PetscLogRegistryGetNumStages(PetscLogRegistry registry, PetscInt *num_stages, PetscInt *max_stages)
73 {
74   PetscFunctionBegin;
75   PetscCall(PetscLogStageArrayGetSize(registry->stages, num_stages, max_stages));
76   PetscFunctionReturn(PETSC_SUCCESS);
77 }
78 
79 PETSC_INTERN PetscErrorCode PetscLogRegistryGetNumClasses(PetscLogRegistry registry, PetscInt *num_classes, PetscInt *max_classes)
80 {
81   PetscFunctionBegin;
82   PetscCall(PetscLogClassArrayGetSize(registry->classes, num_classes, max_classes));
83   PetscFunctionReturn(PETSC_SUCCESS);
84 }
85 
86 PETSC_INTERN PetscErrorCode PetscLogRegistryStageRegister(PetscLogRegistry registry, const char sname[], int *stage)
87 {
88   int               idx;
89   PetscLogStageInfo stage_info;
90 
91   PetscFunctionBegin;
92   PetscCall(PetscLogStageArrayFind(registry->stages, sname, &idx));
93   PetscCheck(idx == -1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "An event named %s is already registered", sname);
94   *stage = registry->stages->num_entries;
95   PetscCall(PetscStrallocpy(sname, &stage_info.name));
96   PetscCall(PetscLogStageArrayPush(registry->stages, stage_info));
97   PetscFunctionReturn(PETSC_SUCCESS);
98 }
99 
100 PETSC_INTERN PetscErrorCode PetscLogRegistryEventRegister(PetscLogRegistry registry, const char name[], PetscClassId classid, PetscLogEvent *event)
101 {
102   PetscLogEventInfo new_info;
103 
104   PetscFunctionBegin;
105   PetscCall(PetscLogRegistryGetEventFromName(registry, name, event));
106   if (*event >= 0) PetscFunctionReturn(PETSC_SUCCESS);
107   *event              = registry->events->num_entries;
108   new_info.classid    = classid;
109   new_info.collective = PETSC_TRUE;
110   PetscCall(PetscStrallocpy(name, &new_info.name));
111   PetscCall(PetscLogEventArrayPush(registry->events, new_info));
112   PetscFunctionReturn(PETSC_SUCCESS);
113 }
114 
115 PETSC_INTERN PetscErrorCode PetscLogRegistryClassRegister(PetscLogRegistry registry, const char name[], PetscClassId classid, PetscLogClass *clss)
116 {
117   PetscLogClassInfo new_info;
118 
119   PetscFunctionBegin;
120   PetscCall(PetscLogRegistryGetClassFromClassId(registry, classid, clss));
121   if (*clss >= 0) PetscFunctionReturn(PETSC_SUCCESS);
122   *clss            = registry->classes->num_entries;
123   new_info.classid = classid;
124   PetscCall(PetscStrallocpy(name, &new_info.name));
125   PetscCall(PetscLogClassArrayPush(registry->classes, new_info));
126   PetscFunctionReturn(PETSC_SUCCESS);
127 }
128 
129 PETSC_INTERN PetscErrorCode PetscLogRegistryGetEventFromName(PetscLogRegistry registry, const char name[], PetscLogEvent *event)
130 {
131   PetscFunctionBegin;
132   PetscCall(PetscLogEventArrayFind(registry->events, name, event));
133   PetscFunctionReturn(PETSC_SUCCESS);
134 }
135 
136 PETSC_INTERN PetscErrorCode PetscLogRegistryGetStageFromName(PetscLogRegistry registry, const char name[], PetscLogStage *stage)
137 {
138   PetscFunctionBegin;
139   PetscCall(PetscLogStageArrayFind(registry->stages, name, stage));
140   PetscFunctionReturn(PETSC_SUCCESS);
141 }
142 
143 PETSC_INTERN PetscErrorCode PetscLogRegistryGetClassFromClassId(PetscLogRegistry registry, PetscClassId classid, PetscLogStage *clss)
144 {
145   PetscLogClassInfo key;
146 
147   PetscFunctionBegin;
148   key.name    = NULL;
149   key.classid = classid;
150   PetscCall(PetscLogClassArrayFind(registry->classes, &key, clss));
151   PetscFunctionReturn(PETSC_SUCCESS);
152 }
153 
154 PETSC_INTERN PetscErrorCode PetscLogRegistryGetClassFromName(PetscLogRegistry registry, const char name[], PetscLogStage *clss)
155 {
156   PetscLogClassInfo key;
157 
158   PetscFunctionBegin;
159   key.name    = (char *)name;
160   key.classid = -1;
161   PetscCall(PetscLogClassArrayFind(registry->classes, &key, clss));
162   PetscFunctionReturn(PETSC_SUCCESS);
163 }
164 
165 PETSC_INTERN PetscErrorCode PetscLogRegistryEventGetInfo(PetscLogRegistry registry, PetscLogEvent event, PetscLogEventInfo *event_info)
166 {
167   PetscFunctionBegin;
168   PetscCall(PetscLogEventArrayGet(registry->events, event, event_info));
169   PetscFunctionReturn(PETSC_SUCCESS);
170 }
171 
172 PETSC_INTERN PetscErrorCode PetscLogRegistryStageGetInfo(PetscLogRegistry registry, PetscLogStage stage, PetscLogStageInfo *stage_info)
173 {
174   PetscFunctionBegin;
175   PetscCall(PetscLogStageArrayGet(registry->stages, stage, stage_info));
176   PetscFunctionReturn(PETSC_SUCCESS);
177 }
178 
179 PETSC_INTERN PetscErrorCode PetscLogRegistryClassGetInfo(PetscLogRegistry registry, PetscLogClass clss, PetscLogClassInfo *class_info)
180 {
181   PetscFunctionBegin;
182   PetscCall(PetscLogClassArrayGet(registry->classes, clss, class_info));
183   PetscFunctionReturn(PETSC_SUCCESS);
184 }
185 
186 PETSC_INTERN PetscErrorCode PetscLogRegistryEventSetCollective(PetscLogRegistry registry, PetscLogEvent event, PetscBool collective)
187 {
188   PetscLogEventInfo *event_info;
189 
190   PetscFunctionBegin;
191   PetscCall(PetscLogEventArrayGetRef(registry->events, event, &event_info));
192   event_info->collective = collective;
193   PetscFunctionReturn(PETSC_SUCCESS);
194 }
195 
196 /* Given a list of strings on each process, create a global numbering.  Order
197  them by their order on the first process, then the remaining by their order
198  on the second process, etc.  The expectation is that most processes have the
199  same names in the same order so it shouldn't take too many rounds to figure
200  out */
201 
202 struct _n_PetscLogGlobalNames {
203   MPI_Comm     comm;
204   PetscInt     count_global;
205   PetscInt     count_local;
206   const char **names;
207   PetscInt    *global_to_local;
208   PetscInt    *local_to_global;
209 };
210 
211 static PetscErrorCode PetscLogGlobalNamesCreate_Internal(MPI_Comm comm, PetscInt num_names_local, const char **names, PetscInt *num_names_global_p, PetscInt **global_index_to_local_index_p, PetscInt **local_index_to_global_index_p, const char ***global_names_p)
212 {
213   PetscMPIInt size, rank;
214   PetscInt    num_names_global          = 0;
215   PetscInt    num_names_local_remaining = num_names_local;
216   PetscBool  *local_name_seen;
217   PetscInt   *global_index_to_local_index = NULL;
218   PetscInt   *local_index_to_global_index = NULL;
219   PetscInt    max_name_len                = 0;
220   char       *str_buffer;
221   char      **global_names = NULL;
222   PetscMPIInt p;
223 
224   PetscFunctionBegin;
225   PetscCallMPI(MPI_Comm_size(comm, &size));
226   if (size == 1) {
227     PetscCall(PetscMalloc1(num_names_local, &global_index_to_local_index));
228     PetscCall(PetscMalloc1(num_names_local, &local_index_to_global_index));
229     PetscCall(PetscMalloc1(num_names_local, &global_names));
230     for (PetscInt i = 0; i < num_names_local; i++) {
231       global_index_to_local_index[i] = i;
232       local_index_to_global_index[i] = i;
233       PetscCall(PetscStrallocpy(names[i], &global_names[i]));
234     }
235     *num_names_global_p            = num_names_local;
236     *global_index_to_local_index_p = global_index_to_local_index;
237     *local_index_to_global_index_p = local_index_to_global_index;
238     *global_names_p                = (const char **)global_names;
239     PetscFunctionReturn(PETSC_SUCCESS);
240   }
241   PetscCallMPI(MPI_Comm_rank(comm, &rank));
242   PetscCall(PetscCalloc1(num_names_local, &local_name_seen));
243   PetscCall(PetscMalloc1(num_names_local, &local_index_to_global_index));
244 
245   for (PetscInt i = 0; i < num_names_local; i++) {
246     size_t i_len;
247     PetscCall(PetscStrlen(names[i], &i_len));
248     max_name_len = PetscMax(max_name_len, (PetscInt)i_len);
249   }
250   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &max_name_len, 1, MPIU_INT, MPI_MAX, comm));
251   PetscCall(PetscCalloc1(max_name_len + 1, &str_buffer));
252 
253   p = 0;
254   while (p < size) {
255     PetscInt my_loc, next_loc;
256     PetscInt num_to_add;
257 
258     my_loc = num_names_local_remaining > 0 ? rank : PETSC_MPI_INT_MAX;
259     PetscCallMPI(MPIU_Allreduce(&my_loc, &next_loc, 1, MPIU_INT, MPI_MIN, comm));
260     if (next_loc == PETSC_MPI_INT_MAX) break;
261     PetscAssert(next_loc >= p, comm, PETSC_ERR_PLIB, "Failed invariant, expected increasing next process");
262     p          = next_loc;
263     num_to_add = (rank == p) ? num_names_local_remaining : -1;
264     PetscCallMPI(MPI_Bcast(&num_to_add, 1, MPIU_INT, p, comm));
265     {
266       PetscInt  new_num_names_global = num_names_global + num_to_add;
267       PetscInt *new_global_index_to_local_index;
268       char    **new_global_names;
269 
270       PetscCall(PetscMalloc1(new_num_names_global, &new_global_index_to_local_index));
271       PetscCall(PetscArraycpy(new_global_index_to_local_index, global_index_to_local_index, num_names_global));
272       for (PetscInt i = num_names_global; i < new_num_names_global; i++) new_global_index_to_local_index[i] = -1;
273       PetscCall(PetscFree(global_index_to_local_index));
274       global_index_to_local_index = new_global_index_to_local_index;
275 
276       PetscCall(PetscCalloc1(new_num_names_global, &new_global_names));
277       PetscCall(PetscArraycpy(new_global_names, global_names, num_names_global));
278       PetscCall(PetscFree(global_names));
279       global_names = new_global_names;
280     }
281 
282     if (rank == p) {
283       for (PetscInt s = 0; s < num_names_local; s++) {
284         if (local_name_seen[s]) continue;
285         local_name_seen[s] = PETSC_TRUE;
286         PetscCall(PetscArrayzero(str_buffer, max_name_len + 1));
287         PetscCall(PetscStrallocpy(names[s], &global_names[num_names_global]));
288         PetscCall(PetscStrncpy(str_buffer, names[s], max_name_len + 1));
289         PetscCallMPI(MPI_Bcast(str_buffer, max_name_len + 1, MPI_CHAR, p, comm));
290         local_index_to_global_index[s]                  = num_names_global;
291         global_index_to_local_index[num_names_global++] = s;
292         num_names_local_remaining--;
293       }
294     } else {
295       for (PetscInt i = 0; i < num_to_add; i++) {
296         PetscInt s;
297         PetscCallMPI(MPI_Bcast(str_buffer, max_name_len + 1, MPI_CHAR, p, comm));
298         PetscCall(PetscStrallocpy(str_buffer, &global_names[num_names_global]));
299         for (s = 0; s < num_names_local; s++) {
300           PetscBool same;
301 
302           if (local_name_seen[s]) continue;
303           PetscCall(PetscStrncmp(names[s], str_buffer, max_name_len + 1, &same));
304           if (same) {
305             local_name_seen[s]                            = PETSC_TRUE;
306             global_index_to_local_index[num_names_global] = s;
307             local_index_to_global_index[s]                = num_names_global;
308             num_names_local_remaining--;
309             break;
310           }
311         }
312         if (s == num_names_local) {
313           global_index_to_local_index[num_names_global] = -1; // this name is not present on this process
314         }
315         num_names_global++;
316       }
317     }
318   }
319 
320   PetscCall(PetscFree(str_buffer));
321   PetscCall(PetscFree(local_name_seen));
322   *num_names_global_p            = num_names_global;
323   *global_index_to_local_index_p = global_index_to_local_index;
324   *local_index_to_global_index_p = local_index_to_global_index;
325   *global_names_p                = (const char **)global_names;
326 
327   PetscFunctionReturn(PETSC_SUCCESS);
328 }
329 
330 PETSC_INTERN PetscErrorCode PetscLogGlobalNamesCreate(MPI_Comm comm, PetscInt num_names_local, const char **local_names, PetscLogGlobalNames *global_names_p)
331 {
332   PetscLogGlobalNames global_names;
333 
334   PetscFunctionBegin;
335   PetscCall(PetscNew(&global_names));
336   PetscCall(PetscLogGlobalNamesCreate_Internal(comm, num_names_local, local_names, &global_names->count_global, &global_names->global_to_local, &global_names->local_to_global, &global_names->names));
337   global_names->count_local = num_names_local;
338   *global_names_p           = global_names;
339   PetscFunctionReturn(PETSC_SUCCESS);
340 }
341 
342 PETSC_INTERN PetscErrorCode PetscLogGlobalNamesDestroy(PetscLogGlobalNames *global_names_p)
343 {
344   PetscLogGlobalNames global_names;
345 
346   PetscFunctionBegin;
347   global_names    = *global_names_p;
348   *global_names_p = NULL;
349   PetscCall(PetscFree(global_names->global_to_local));
350   PetscCall(PetscFree(global_names->local_to_global));
351   for (PetscInt i = 0; i < global_names->count_global; i++) { PetscCall(PetscFree(global_names->names[i])); }
352   PetscCall(PetscFree(global_names->names));
353   PetscCall(PetscFree(global_names));
354   PetscFunctionReturn(PETSC_SUCCESS);
355 }
356 
357 PETSC_INTERN PetscErrorCode PetscLogGlobalNamesGlobalGetName(PetscLogGlobalNames global_names, PetscInt idx, const char **name)
358 {
359   PetscFunctionBegin;
360   PetscCheck(idx >= 0 && idx < global_names->count_global, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Idx %d not in range [0,%d)", (int)idx, (int)global_names->count_global);
361   *name = global_names->names[idx];
362   PetscFunctionReturn(PETSC_SUCCESS);
363 }
364 
365 PETSC_INTERN PetscErrorCode PetscLogGlobalNamesGlobalGetLocal(PetscLogGlobalNames global_names, PetscInt idx, PetscInt *local_idx)
366 {
367   PetscFunctionBegin;
368   PetscCheck(idx >= 0 && idx < global_names->count_global, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Idx %d not in range [0,%d)", (int)idx, (int)global_names->count_global);
369   *local_idx = global_names->global_to_local[idx];
370   PetscFunctionReturn(PETSC_SUCCESS);
371 }
372 
373 PETSC_INTERN PetscErrorCode PetscLogGlobalNamesLocalGetGlobal(PetscLogGlobalNames global_names, PetscInt local_idx, PetscInt *idx)
374 {
375   PetscFunctionBegin;
376   PetscCheck(local_idx >= 0 && local_idx < global_names->count_local, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Idx %d not in range [0,%d)", (int)local_idx, (int)global_names->count_local);
377   *idx = global_names->local_to_global[local_idx];
378   PetscFunctionReturn(PETSC_SUCCESS);
379 }
380 
381 PETSC_INTERN PetscErrorCode PetscLogGlobalNamesGetSize(PetscLogGlobalNames global_names, PetscInt *local_size, PetscInt *global_size)
382 {
383   PetscFunctionBegin;
384   if (local_size) *local_size = global_names->count_local;
385   if (global_size) *global_size = global_names->count_global;
386   PetscFunctionReturn(PETSC_SUCCESS);
387 }
388 
389 PETSC_INTERN PetscErrorCode PetscLogRegistryCreateGlobalStageNames(MPI_Comm comm, PetscLogRegistry registry, PetscLogGlobalNames *global_names_p)
390 {
391   PetscInt     num_stages_local;
392   const char **names;
393 
394   PetscFunctionBegin;
395   PetscCall(PetscLogStageArrayGetSize(registry->stages, &num_stages_local, NULL));
396   PetscCall(PetscMalloc1(num_stages_local, &names));
397   for (PetscInt i = 0; i < num_stages_local; i++) {
398     PetscLogStageInfo stage_info = {NULL};
399     PetscCall(PetscLogRegistryStageGetInfo(registry, i, &stage_info));
400     names[i] = stage_info.name;
401   }
402   PetscCall(PetscLogGlobalNamesCreate(comm, num_stages_local, names, global_names_p));
403   PetscCall(PetscFree(names));
404   PetscFunctionReturn(PETSC_SUCCESS);
405 }
406 
407 PETSC_INTERN PetscErrorCode PetscLogRegistryCreateGlobalEventNames(MPI_Comm comm, PetscLogRegistry registry, PetscLogGlobalNames *global_names_p)
408 {
409   PetscInt     num_events_local;
410   const char **names;
411 
412   PetscFunctionBegin;
413   PetscCall(PetscLogEventArrayGetSize(registry->events, &num_events_local, NULL));
414   PetscCall(PetscMalloc1(num_events_local, &names));
415   for (PetscInt i = 0; i < num_events_local; i++) {
416     PetscLogEventInfo event_info = {NULL, 0, PETSC_FALSE};
417 
418     PetscCall(PetscLogRegistryEventGetInfo(registry, i, &event_info));
419     names[i] = event_info.name;
420   }
421   PetscCall(PetscLogGlobalNamesCreate(comm, num_events_local, names, global_names_p));
422   PetscCall(PetscFree(names));
423   PetscFunctionReturn(PETSC_SUCCESS);
424 }
425