Hi Akim, > > 1) Simplify. I don't see the point of the DEFTIMEVAR layer with the enum. > > Couldn't the code just do > > timevar_t tv_total; > > timevar_t tv_reader; > > .. > > and > > init_timevar (); > > timevar_start (&tv_total); > > > > timevar_push (&tv_reader); > > reader (); > > timevar_pop (&tv_reader); > > I’m not sure I understand what you mean here. The timers are > used in many places in the code, not just main(). We need some > global definition somewhere, and we want to iterate over them > when displaying the result.
OK, you have now stated the requirement. From an abstract point of view, you have a list of globally defined objects, where "list" means a data structure suitable for iteration. The IDs are only implementation artifacts for the current implementation. I can imagine four ways to implement such a list: a) Through a separate file, which gets included at different places in the code. DEFTIMEVAR (TV_TOTAL , "total time") DEFTIMEVAR (TV_READER , "reader") ... b) Through a set of global variables and a globally allocated array: timevar_t tv_total = { "total time" }; timevar_t tv_reader = { "reader" }; ... timevar_t* all_timevars[] = { &tv_total, &tv_reader, ... }; c) Through a globally allocated array and a couple of convenience macros: timevar_t all_timevars[] = { { "total time" }, #define tv_total &all_timevars[0] { "reader" }, #define tv_reader &all_timevars[1] ... }; d) Through a set of global variables and a list constructed at run time: timevar_t tv_total = { "total time" }; timevar_t tv_reader = { "reader" }; ... gl_list_t all_timevars; void init_timevars (void) { ... all_timevars = gl_list_create_empty (GL_ARRAY_LIST, NULL, NULL, NULL, true); gl_list_add_last (all_timevars, &tv_total); gl_list_add_last (all_timevars, &tv_reader); ... } What I mean is that each approach has different benefits. Approach (a) has the benefit that adding a new timevar is easy: just one modification in a single place. The drawback is that - you need one extra source code file, - the developer needs to understand the abstraction (the fact that it's an iterable list of globally defined objects was not explicitly stated), - you need the artificial concept of the ID, - not much flexibility (e.g. you cannot process the list in reverse order, you cannot define a tree or list-of-lists instead of a list). Approaches (b), (c), (d) have the advantage that the abstraction is easier to understand, because it follows common C idioms (define structs and reference them through pointers instead of IDs). And they add flexibility: If someone wants a list-of-lists instead of a single list, it's obvious how to do the change. The drawbacks are: (b): To add a new timevar, two places in the code need to be touched. (c): none (d): To add a new timevar, two places in the code need to be touched. Note that (c), like (a), has the benefit that adding a new timevar is a modification in a single place. (d) has the further big advantage that the list can be configured at run time. For example, if a compiler has dynamically loadable passes (like GNU ld), this is essential. What do you think? Do you think the list-of-lists use-case makes sense? Do you think configuring the list at run time is something people may want to do? Bruno