Global variables

From ASCEND
Jump to: navigation, search
This article is about planned development or proposed functionality. Comments welcome.

We would like to get rid of the current use of global variables in ASCEND, so that we can start to think about using ASCEND in multithreaded and/or embedded ways. This page will report any cases of global variables that we have found, and perhaps some discussion about how we can best eliminate them. Not all cases will be the same. Globals make some aspects of code reading easier (not crowding C arg lists with context pointers) and some harder: when complex side effects are in play. We try hard to avoid any usage of globals with complex side effects.

Ways for removing global variables

A number of options exist:

  • keeping them. This is appropriate in a very limited set of situations, such as for data that has been loaded from a configuration file when the program started.
  • groupin them into a top-level data structure. We imagine structures like "library", "simulation" and "system" could be created that could hold most global variables.
  • passing them. Where global variables have been used as a convenience to avoid having to expand function parameter lists, we can just change to passing them as parameters.
  • converting them to #defines. May be appropriate for certain constants.
  • converting them to thread-local variables (may need to assess implication for embedded applications)
  • adding mutex constraints (so that they can only be accessed once at a time)
  • migrating them to another code layer, eg into the GUI (this has already been done in some cases)

Particular kinds of usage and what can be done about it

  • Lex/Yacc C based scanners and parsers (and some still current versions of GNU bison/flex) generate code full of globals and non-threadsafe functions. It's not our job to fix this. The 'safe' thing to do is put a mutex around the parse function.
  • ASCEND defined parser context flags, once properly identified, can remain global because the mutex for yacc will also protect them. Cosmetically, the 'properly identified' problem could be resolved by collecting these variables into a single well-named struct g_parser_context.
  • Type library globals: most of these should be moved into a formal struct ascUniverse. More about that below.
  • Instantiator tuning: most of these should be moved into a struct ascCompilerTuning.
  • Memory recycle pools of small objects, tied to globals. These are tied to globals (typically file-scope static variables hidden behind allocator functions) to avoid passing pool pointers everywhere. In solvers like linsolqr, these pools should be tied to major objects instead of file global. "Too many pool objects, too short lived" is a problem that can be solved (taking mtx as an example, perhaps) by maintaining a list of idle mtx element pools; when to clear the idle pools is a minor problem. In the compiler, many pools should come and go with their Universe or with the destruction of the ascend type list and all dependent instances.

The object lives in ascend, and a design for global use reduction

The most basic facts: ascend parses a set of type definitions into a self-consistent class hierarchy. These type definitions can then be used with the instantiator to create model instances with relation and variable data. These instance objects answer many queries by accessing pointers to the type definitions used to create the objects. ASCEND has a concept named UNIVERSAL (not unlike globals in C) whereby for a given type definition, only one instance will ever be constructed. Both types and instances are deeply tied to a symbol (constant strings) table. Throughout ascend, both types and symbols are heavily compared for identity by comparing pointers.

Key outcome of the above: if we wrap all the compiler globals in a context object of universal scope, we can then have at a higher (scripting) level multiple universe objects. **Objects from distinct universes cannot be compared except in string form** !

Given the above, then, ascend model type and instance data can be organized into something like the following. I will use c++ notation, but the implementation will be C. When in the parser, a single global (the universe pointer for the parsing to operate within) is needed and a mutex.

class ascUniverse {
public:
// functions only
private:
int auid; // serial number of this universe
struct ascUniverse *next;
// struct Symtab symtab;
// memory pools for statement, vlist, etc, etc
// struct Simlist simlist;
// struct Library library
// etc
static struct ascUniverse * g_universe_list;
};

Many parts within the compiler will need only a pointer to the piece of the universe where their data lives; we should not be passing universe pointers everywhere in the compiler. Implementing all this correctly as a refactorization is extremely tedious and should only be done with a test suite and automated refactoring tools.

Global variables in libascend.so

The main place where global variables are a problem for ASCEND is in libascend, our core library include the ASCEND parser/compiler and evaluation routines, but hopefully excluding the solvers.

Below is a list of globals generated using GNU nm.

john@thunder:~/ascend$ nm libascend.so  | grep -i " [DdGgSsBb] ";
001828a0 b AllowedContents
00926420 b BracesNestLevel
0092889c b CmpEv
0092641c b CommentNestLevel
00180be0 d DimNames
00927ac8 b EvaluatingSets
00926548 b FundamentalTypeList
00928528 b GlobalUniversalTable
00927c14 b InterfaceNotify
00927c0c b InterfacePtrATS
00927c10 b InterfacePtrDelete
00928790 b L.6247
0092879c b L.6717
0092bca0 b LibraryHashTable
00927ac4 b ListMode
00926424 b MatchedBackslash
00927a64 b MinusOne
00927a84 b One
001820c0 b RecycledContents
001818e0 b RecycledList
00926428 b RequireIndex
00926460 b RequireStack
009286e0 B Solv_C_CheckHalt_Flag
00927aa4 b Three
00927a94 b Two
001816a0 d VpTable
009300dc b X
00927a74 b Zero
0017fcc0 d __CTOR_END__
0017fcbc d __CTOR_LIST__
0017fcc8 d __DTOR_END__
0017fcc4 d __DTOR_LIST__
0017fccc d __JCR_END__
0017fccc d __JCR_LIST__
00180a20 d __dso_handle
00181811 d blockend
001817fc d blockmagic
001814fc D calc_ok
00181500 d calc_print_errors
00928338 b cap.11161
009286d8 b cap.7377
00181520 d commands
001818a0 b completed.6625
009300e0 b conopt_fptrs
00927a54 b constants_inited
001817d0 d csdata
00183088 b dcps.2434
00926488 b default_library_path.7912
0092648c b default_solvers_path.7911
0018167c d defaultintegrators.6720
00927a60 b deriv_store.5961
00926564 b done.4160
00183090 b dref.2433
00927c80 b ds.3670
00927d60 b ds.4078
00928540 b ds.4252
00928060 b ds.4837
00928140 b ds.5578
001818a4 b dtor_idx.6627
009287c8 b elt.4095
009287cc b elt.4148
00926430 b errcount.6732
009263a4 b errcount.8155
00181670 d errname.6760
00928384 b error_statement_sym.4928
00928800 b exception_buffer
009287e0 b exception_status
00180a24 d f_first
00180a28 d f_fpe_top_of_stack
00926364 b f_fpe_traps
00180a2c d f_int_top_of_stack
00926368 b f_int_traps
001830e0 b f_mem_rec
001830c8 b f_memory_allocated
001830c4 b f_memory_length
001830c0 b f_memory_log_file
009242e0 b f_panic_callback_func
001830cc b f_peak_memory_usage
00180a30 d f_seg_top_of_stack
0092636c b f_seg_traps
00925300 b g_Asc_printVtables
00927acc b g_DeclarativeContext
00181320 d g_DefinitionErrorMessages
00927abc b g_EvaluationContext
00927ac0 b g_EvaluationForTable
00927ab8 b g_ExtVariablesTable
00927ab4 b g_ExternalFuncLibrary
00928018 b g_ExternalNodeStamps
00180e60 d g_abs_f
001812b0 D g_alt_ending
00926490 b g_ammarking
00180f20 d g_arccos_f
001810a0 d g_arccosh_f
00180ee0 d g_arcsin_f
00181060 d g_arcsinh_f
00180f60 d g_arctan_f
001810e0 d g_arctanh_f
00926494 b g_array_child_pool
00928444 b g_array_desc_count
00928448 b g_array_desc_list
0018309c b g_ascend_dllist
009264c0 b g_atom_bytes
009263b0 b g_atom_dim_ptr
0092bc50 b g_b_inst
0018187c d g_ba_elimdata
0092bc6c b g_ba_inst
0092863c b g_bad_rel_in_list
0092bc7c b g_bc_inst
00928434 b g_big_strings
00928438 b g_big_strings_cnt
00928640 b g_blockmethod
00180a60 d g_bt_data
00926398 b g_callargs
0092864c b g_case_number
00928030 b g_cbbccount
0092802c b g_cbbdcount
00181160 d g_cbrt_f
001812ec D g_check_dimensions_noisy
00926514 b g_clique_list
00181208 D g_compiler_counter
00928360 B g_compiler_timing
00180a34 D g_compiler_warnings
0092649c b g_cons
009263a0 b g_constant_type
009279d4 b g_copy_numnodes
00180d60 d g_cos_f
00180fe0 d g_cosh_f
00181120 d g_cube_f
00927f54 b g_current_module
0092bc48 b g_cursim
00926544 b g_def_child_bit_list
00926540 b g_def_child_desc_ptr
0092653c b g_def_child_list_ptr
009263b4 b g_default_dim_ptr
009263b8 b g_default_double
009263c0 b g_default_long
00928b4c b g_default_symbol
009263a8 b g_defaulted
00926534 b g_diagf
009263ac b g_dim_ptr
0092ac38 B g_dimen_list
0092ac30 b g_dimensionless
009286b4 b g_dis_tag
009284c0 b g_drt_depth
00927c28 b g_dummy_type
0092ac40 b g_dump_ht
0092bc40 b g_dump_inst_count
0092bc44 b g_dump_type_count
00926384 b g_end_identifier
001830a0 b g_env_list
00925340 b g_error_reporter_cache
00925328 b g_error_reporter_callback
00925320 b g_error_reporter_tree
00925324 b g_error_reporter_tree_current
00180c20 d g_exp_f
00927a50 b g_exprs_pool
00927c34 b g_externalmodel_type
009264fc b g_extra_parents
00926500 b g_extra_parents_sum
009264f8 b g_extra_paths
009288a0 b g_foreign_code_call_env
00927ad0 b g_forvar_recycle_list
00927ad4 b g_forvarfile
009289e0 B g_fpe_env
00927ad8 b g_free_store
001811a0 d g_func_list
00926370 b g_header_linenum
00180ea0 d g_hold_f
0092bc5c b g_i_inst
0092bc74 b g_ia_inst
0092bc60 b g_ic_inst
0017fce0 d g_instancetypenames
0018120c d g_instantiate_relns
00928a80 B g_int_env
001814f8 d g_iscomplete
0092844c b g_it_dummy_enum
00181310 d g_it_dummy_int
00927c00 b g_iteration
009284a8 b g_lcl_head
009284b8 b g_lcl_length
009284b4 b g_lcl_pivot
009284b0 b g_lcl_recycle
009284ac b g_lcl_tail
009284bc b g_lclrecycle_length
00181740 D g_linsolqr_timing
001818c0 b g_list_head_pool
00180c60 d g_ln_f
00180c08 D g_lnm_epsilon
00180ca0 d g_lnm_f
00180ce0 d g_log10_f
00927e40 b g_log_shortbuf
00927d54 b g_logrel_stack
00927c24 b g_logrel_type
00927f44 b g_logrelation_bvar_list
00927f48 b g_logrelation_satrel_list
00927f50 b g_logterm_pool
00181288 d g_logterm_ptrs
00927e34 b g_logwritfp
0092bc54 b g_lrel_inst
0092650c b g_maximum_children
009264f4 b g_maximum_parents
00926520 b g_maximum_relations
00926508 b g_minimum_children
009264f0 b g_minimum_parents
0092651c b g_minimum_relations
00926560 b g_missing
0092bc88 b g_mod_inst
009264b8 b g_model_bytes
00928000 b g_model_definition_methods
00926388 b g_model_parameters
00927f5c b g_module_list
00181220 d g_mpi_message
009287c4 b g_mtx_debug_redirect
0018185c d g_mtx_null_col_vector_data
0018181c d g_mtx_null_index_data
0018183c d g_mtx_null_mark_data
0018186c d g_mtx_null_row_vector_data
0018182c d g_mtx_null_sum_data
0018184c d g_mtx_null_vector_data
009301b4 b g_mtxerr
00927f6c b g_name_pool
009279e0 b g_names_needed
00927a58 b g_new_var_list
0092639c b g_notelist
00927f70 b g_notes_data_base
009264e8 b g_num_array_instances
009264dc b g_num_atom_children
009264bc b g_num_atom_instances
009264b0 b g_num_complex_instances
009264d8 b g_num_constant_all
009264cc b g_num_constant_bool
009264d0 b g_num_constant_int
009264c8 b g_num_constant_real
009264d4 b g_num_constant_sym
009264b4 b g_num_model_instances
00927f64 b g_num_names_cur
00927f68 b g_num_names_max
009264e0 b g_num_relation_instances
009264ec b g_num_unsel_instances
009284a4 b g_number
00927f90 b g_numlist_head_pool
00924300 b g_panic_outfile
00926390 b g_parameter_reduction
0092638c b g_parameter_wheres
0018130c d g_parse_count
00180a38 d g_parse_relns
009284c4 B g_parser_warnings
00927f9c b g_pending_count
00927fa0 b g_pending_list
00927fa4 b g_pending_list_end
00927fa8 b g_pending_pool
0092cca0 B g_plot_type
00927f94 b g_ppe_pool
001811fc d g_proc
00926378 b g_proc_name
00928004 b g_procframe_stop
00928008 b g_proto_count
0092ccc0 b g_proto_ht
0092bc94 b g_r_inst
0092bc78 b g_ra_inst
0092bc64 b g_rc_inst
00927a00 b g_recycle_expreval_stacks
00927f84 b g_recycled_npl
00926380 b g_refines_name
0092bc84 b g_rel_inst
00928040 b g_rel_stack
00928044 b g_rel_stack_pool
009264e4 b g_relation_guts
0092652c b g_relation_terms
00927c20 b g_relation_type
00928014 b g_relation_var_list
00928010 B g_relative_inst
00928618 b g_reuse
009286c4 b g_reuse
0092bc58 b g_s_inst
0092bc80 b g_sa_inst
0092bc90 b g_sc_inst
0092800c B g_search_inst
00928940 B g_seg_env
00928354 b g_set_pool
00927c30 b g_set_type
00928358 b g_sets_pool
00928220 b g_shortbuf
001812f4 d g_show_statement_detail
00927f4c b g_simplify_logrelations
001812cc D g_simplify_relations
0092835c B g_simulation_list
00180d20 d g_sin_f
00180fa0 d g_sinh_f
00927f60 b g_sldestroy
0092877c b g_solver_binary_type
009286c0 b g_solver_dis_type
00928778 b g_solver_int_type
00928780 b g_solver_semi_type
00928774 b g_solver_var_type
00180de0 d g_sqr_f
00180e20 d g_sqrt_f
00928414 b g_statio_flowtypenames
001812f8 d g_statio_label
009283a0 b g_statio_stattypenames
00928380 b g_statio_suppressions
00927b00 b g_string_buffer
00927f58 b g_string_modules_processed
00928428 b g_string_space
00927fc0 b g_strings
00928624 b g_strings
009286b8 b g_strings
009286d0 b g_strings
009286d4 b g_strings
00928758 b g_strings
00926498 b g_suppressions
0092bc8c b g_sym_inst
0092bc4c b g_syma_inst
00928430 b g_symbol_collisions
0092842c b g_symbol_size
0092dcc0 b g_symbol_table
00928614 b g_symbol_values_list
00927c40 b g_symbols
00928460 b g_symbols
009287ac b g_symbols
0092bc68 b g_symc_inst
00180da0 d g_tan_f
00181020 d g_tanh_f
0092843c b g_temporary_var_list
00928440 b g_temporary_var_recycle
0092801c b g_term_pool
001812d0 d g_term_ptrs
009284c8 b g_tlibs_depth
0092ab80 b g_token_counts
00926530 b g_total_array_children
00926510 b g_total_children
00926504 b g_total_parents
00926528 b g_total_reals_in_rels
00926524 b g_total_relations
00926518 b g_total_variables
009264c4 b g_tree_bytes
0092ac34 b g_trig_dimen
00927c04 b g_trychildexpansion_errmessage
009264ac b g_type_count_list
0092637c b g_type_name
00926394 b g_typeargs
00927c08 b g_unasscon_count
00928500 b g_unit_base_name
009284f0 b g_unit_explain_error_strings
00927adc b g_units_alloc
009284ec b g_units_collisions
001814c0 d g_units_errors.4640
0092f0e0 B g_units_hash_table
0092ecc0 b g_units_id_space
009263c4 b g_units_ptr
009284e8 b g_units_size
009284e0 b g_units_str
009284e4 b g_units_str_len
00927f98 b g_unresolved_count
00926374 b g_untrapped_error
00181204 D g_use_copyanon
0092852c b g_value_pool
00928754 b g_var_tag
0092bc70 b g_when_inst
00927c2c b g_when_type
0092ac3c b g_wild_dimen
0092642c b g_workbuf
00180a44 d g_workbuf_len.6555
00928214 b g_writfp
00928348 b glob_done
00927f40 b glob_lrel
00928340 b glob_rel
00928344 b glob_varnum
009279d0 b global_command_list
00928530 b global_visit_num
009287bc b hhrowlist.6528
00183074 b i.2578
00926354 b i.2755
00927ae0 b importhandler_library
00927ae4 b importhandler_sharedpointers
00926538 b init.5484
00928794 b init.6246
009287a0 b init.6716
0092878c b inst
009287c0 b last_value_matrix
00928798 b lastsolver.6445
00928330 b lhscap.9848
009287b8 b listlen.6529
00928784 b loaded.3887
00180ba0 d metadata.4158
001817e0 d mtxmagic
00928700 b name.6123
00928660 b name.6164
00181744 d names.4315
00181760 d names.4320
0018307c b newsize.2576
0092635c b newsize.2753
00181504 d nextid.6241
001812c8 d nostr.4857
00181688 d nrels.7185
0018168c d nrels.7199
009286fc b nuldev.5971
00181690 d nvars.7213
00183080 b oldsize.2575
00926360 b oldsize.2752
001817f2 d permmagic
00928648 b poly.3808
00928350 b poly.3924
00928644 b poly_cap.3809
0092834c b poly_cap.3925
00927a5c b previous_store.5962
0092833c b ptr.11160
009286dc b ptr.7376
00183078 b punt.2577
00926358 b punt.2754
00183098 b ref.2432
00928334 b rel.9847
009287a4 b reported_already.8633
009287a8 b reported_already.8653
00926580 b result.4159
009286e4 b rfilter.7742
0092832c b rhscap.9849
001817c0 d rsdata
001812f0 d safe_print_errors
0017fda0 d slv_reg
00928320 b soln_list.9691
00926418 b start_line
00928534 b stopnum.3912
00181508 d suppress_rel_flag.6780
00928788 b sys
001812a4 d unk.4785
00925304 b use_xterm_color.2533
009286ec b vfilter.7802
009286f4 b vfilter.7892
00928020 b warnexpt.5603
00928028 b warnexpt.5731
00928024 b warnfdiff.5732
009263f4 b yy_buffer_stack
009263f0 b yy_buffer_stack_max
009263ec b yy_buffer_stack_top
009263f8 b yy_c_buf_p
0092643c b yy_did_buffer_switch_on_eof
00926448 b yy_full_lp
00926440 b yy_full_match
0092644c b yy_full_state
00926434 b yy_hold_char
009263fc b yy_init
00180a40 d yy_line
0092640c b yy_looking_for_trail_begin
00926444 b yy_lp
00926410 b yy_more_offset
00926438 b yy_n_chars
00926414 b yy_prev_more_offset
00926400 b yy_start
00926404 b yy_state_buf
00926408 b yy_state_ptr
0092ab64 b yytext_ptr
009263e8 b zz__flex_debug
00928b50 b zz_char
009263e0 b zz_in
0092ab60 b zz_leng
00180a3c d zz_lineno
00928b20 b zz_lval
00928b54 b zz_nerrs
009263e4 b zz_out
00928b60 b zz_text
john@thunder:~/ascend$

Static variables

Another place where quasi-global variables can occur is as static variables within functions. It needs to be assessed whether the above listing includes those types of variables.