Gaudi Framework, version v23r4

Home   Generated: Mon Sep 17 2012

pfmlib.h

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2001-2007 Hewlett-Packard Development Company, L.P.
00003  * Contributed by Stephane Eranian <eranian@hpl.hp.com>
00004  *
00005  * Permission is hereby granted, free of charge, to any person obtaining a copy
00006  * of this software and associated documentation files (the "Software"), to deal
00007  * in the Software without restriction, including without limitation the rights
00008  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
00009  * of the Software, and to permit persons to whom the Software is furnished to do so,
00010  * subject to the following conditions:
00011  *
00012  * The above copyright notice and this permission notice shall be included in all
00013  * copies or substantial portions of the Software.
00014  *
00015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
00016  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
00017  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
00018  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
00019  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
00020  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00021  */
00022 #ifndef __PFMLIB_H__
00023 #define __PFMLIB_H__
00024 
00025 #ifdef __cplusplus
00026 extern "C" {
00027 #endif
00028 #include <stdio.h>
00029 #include <inttypes.h>
00030 
00031 #include <perfmon/pfmlib_os.h>
00032 #include <perfmon/pfmlib_comp.h>
00033 
00034 #define PFMLIB_VERSION          (3 << 16 | 9)
00035 #define PFMLIB_MAJ_VERSION(v)   ((v)>>16)
00036 #define PFMLIB_MIN_VERSION(v)   ((v) & 0xffff)
00037 
00038 /*
00039  * Maximum number of PMCs/PMDs supported by the library (especially bitmasks)
00040  */
00041 #define PFMLIB_MAX_PMCS         512 /* maximum number of PMCS supported by the library */
00042 #define PFMLIB_MAX_PMDS         512 /* maximum number of PMDS supported by the library */
00043 
00044 /*
00045  * privilege level mask (mask can be combined)
00046  * The interpretation of the level is specific to each
00047  * architecture. Checkout the architecture specific header
00048  * file for more details.
00049  */
00050 #define PFM_PLM0        0x1     /* priv level 0 */
00051 #define PFM_PLM1        0x2     /* priv level 1 */
00052 #define PFM_PLM2        0x4     /* priv level 2 */
00053 #define PFM_PLM3        0x8     /* priv level 3 */
00054 
00055 /*
00056  * type used to describe a set of bits in the mask (container type)
00057  */
00058 typedef unsigned long pfmlib_regmask_bits_t;
00059 
00060 /*
00061  * how many elements do we need to represent all the PMCs and PMDs (rounded up)
00062  */
00063 #if PFMLIB_MAX_PMCS > PFMLIB_MAX_PMDS
00064 #define PFMLIB_REG_MAX  PFMLIB_MAX_PMCS
00065 #else
00066 #define PFMLIB_REG_MAX  PFMLIB_MAX_PMDS
00067 #endif
00068 
00069 #ifndef SWIG
00070 #define __PFMLIB_REG_BV_BITS (sizeof(pfmlib_regmask_bits_t)<<3)
00071 #define PFMLIB_BVSIZE(x) (((x)+(__PFMLIB_REG_BV_BITS)-1) / __PFMLIB_REG_BV_BITS)
00072 #define PFMLIB_REG_BV PFMLIB_BVSIZE(PFMLIB_REG_MAX)
00073 #endif
00074 
00075 typedef struct {
00076         pfmlib_regmask_bits_t bits[PFMLIB_REG_BV];
00077 } pfmlib_regmask_t;
00078 
00079 
00080 #define PFMLIB_MAX_MASKS_PER_EVENT 48 /* maximum number of unit masks per event */
00081 
00082 /*
00083  * event definition for pfmlib_input_param_t
00084  */
00085 typedef struct {
00086         unsigned int    event;          /* event descriptor */
00087         unsigned int    plm;            /* event privilege level mask */
00088         unsigned long   flags;          /* per-event flag */
00089         unsigned int    unit_masks[PFMLIB_MAX_MASKS_PER_EVENT]; /* unit-mask identifiers */
00090         unsigned int    num_masks;      /* number of masks specified in 'unit_masks' */
00091         unsigned long   reserved[2];    /* for future use */
00092 } pfmlib_event_t;
00093 
00094 /*
00095  * generic register definition
00096  */
00097 typedef struct {
00098         unsigned long long      reg_value;      /* register value */
00099         unsigned long long      reg_addr;       /* hardware register addr or index */
00100         unsigned int            reg_num;        /* logical register index (perfmon2) */
00101         unsigned int            reg_reserved1;  /* for future use */
00102         unsigned long           reg_alt_addr;   /* alternate hw register addr of index */
00103 } pfmlib_reg_t;
00104 
00105 /*
00106  * library generic input parameters for pfm_dispatch_event()
00107  */
00108 typedef struct {
00109         unsigned int     pfp_event_count;               /* how many events specified (input) */
00110         unsigned int     pfp_dfl_plm;                   /* default priv level : used when event.plm==0 */
00111         unsigned int     pfp_flags;                     /* set of flags for all events used when event.flags==0*/
00112         unsigned int     reserved1;                     /* for future use */
00113         pfmlib_event_t   pfp_events[PFMLIB_MAX_PMCS];   /* event descriptions */
00114         pfmlib_regmask_t pfp_unavail_pmcs;              /* bitmask of unavailable PMC registers */
00115         unsigned long    reserved[6];                   /* for future use */
00116 } pfmlib_input_param_t;
00117 
00118 /*
00119  * pfp_flags possible values (apply to all events)
00120  */
00121 #define PFMLIB_PFP_SYSTEMWIDE   0x1 /* indicate monitors will be used in a system-wide session */
00122 
00123 /*
00124  * library generic output parameters for pfm_dispatch_event()
00125  */
00126 typedef struct {
00127         unsigned int     pfp_pmc_count;                 /* number of entries in pfp_pmcs */
00128         unsigned int     pfp_pmd_count;                 /* number of entries in pfp_pmds */
00129         pfmlib_reg_t     pfp_pmcs[PFMLIB_MAX_PMCS];     /* PMC registers number and values */
00130         pfmlib_reg_t     pfp_pmds[PFMLIB_MAX_PMDS];     /* PMD registers numbers */
00131         unsigned long    reserved[7];                   /* for future use */
00132 } pfmlib_output_param_t;
00133 
00134 /*
00135  * library configuration options
00136  */
00137 typedef struct {
00138         unsigned int    pfm_debug:1;    /* set in debug  mode */
00139         unsigned int    pfm_verbose:1;  /* set in verbose mode */
00140         unsigned int    pfm_reserved:30;/* for future use */
00141 } pfmlib_options_t;
00142 
00143 /*
00144  * special data type for libpfm error value used to help
00145  * with Python support and in particular for SWIG. By using
00146  * a specific type we can detect library calls and trap errors
00147  * in one SWIG statement as opposed to having to keep track of
00148  * each call individually. Programs can use 'int' safely for
00149  * the return value.
00150  */
00151 typedef int pfm_err_t;                  /* error if !PFMLIB_SUCCESS */
00152 
00153 extern pfm_err_t pfm_set_options(pfmlib_options_t *opt);
00154 extern pfm_err_t pfm_initialize(void);
00155 
00156 extern pfm_err_t pfm_list_supported_pmus(int (*pf)(const char *fmt,...));
00157 extern pfm_err_t pfm_get_pmu_name(char *name, int maxlen);
00158 extern pfm_err_t pfm_get_pmu_type(int *type);
00159 extern pfm_err_t pfm_get_pmu_name_bytype(int type, char *name, size_t maxlen);
00160 extern pfm_err_t pfm_is_pmu_supported(int type);
00161 extern pfm_err_t pfm_force_pmu(int type);
00162 
00163 /*
00164  * pfm_find_event_byname() is obsolete, use pfm_find_event
00165  */
00166 extern pfm_err_t pfm_find_event(const char *str, unsigned int *idx);
00167 extern pfm_err_t pfm_find_event_byname(const char *name, unsigned int *idx);
00168 extern pfm_err_t pfm_find_event_bycode(int code, unsigned int *idx);
00169 extern pfm_err_t pfm_find_event_bycode_next(int code, unsigned int start,
00170                                             unsigned int *next);
00171 extern pfm_err_t pfm_find_event_mask(unsigned int event_idx, const char *str,
00172                                      unsigned int *mask_idx);
00173 extern pfm_err_t pfm_find_full_event(const char *str, pfmlib_event_t *e);
00174 
00175 extern pfm_err_t pfm_get_max_event_name_len(size_t *len);
00176 
00177 extern pfm_err_t pfm_get_num_events(unsigned int *count);
00178 extern pfm_err_t pfm_get_num_event_masks(unsigned int event_idx,
00179                                          unsigned int *count);
00180 extern pfm_err_t pfm_get_event_name(unsigned int idx, char *name,
00181                                     size_t maxlen);
00182 extern pfm_err_t pfm_get_full_event_name(pfmlib_event_t *e, char *name,
00183                                          size_t maxlen);
00184 extern pfm_err_t pfm_get_event_code(unsigned int idx, int *code);
00185 extern pfm_err_t pfm_get_event_mask_code(unsigned int idx,
00186                                          unsigned int mask_idx,
00187                                          unsigned int *code);
00188 extern pfm_err_t pfm_get_event_counters(unsigned int idx,
00189                                         pfmlib_regmask_t *counters);
00190 extern pfm_err_t pfm_get_event_description(unsigned int idx, char **str);
00191 extern pfm_err_t pfm_get_event_code_counter(unsigned int idx, unsigned int cnt,
00192                                             int *code);
00193 extern pfm_err_t pfm_get_event_mask_name(unsigned int event_idx,
00194                                          unsigned int mask_idx,
00195                                          char *name, size_t maxlen);
00196 extern pfm_err_t pfm_get_event_mask_description(unsigned int event_idx,
00197                                                 unsigned int mask_idx,
00198                                                 char **desc);
00199 
00200 extern pfm_err_t pfm_dispatch_events(pfmlib_input_param_t *p,
00201                                      void *model_in,
00202                                      pfmlib_output_param_t *q,
00203                                      void *model_out);
00204 
00205 extern pfm_err_t pfm_get_impl_pmcs(pfmlib_regmask_t *impl_pmcs);
00206 extern pfm_err_t pfm_get_impl_pmds(pfmlib_regmask_t *impl_pmds);
00207 extern pfm_err_t pfm_get_impl_counters(pfmlib_regmask_t *impl_counters);
00208 extern pfm_err_t pfm_get_num_pmds(unsigned int *num);
00209 extern pfm_err_t pfm_get_num_pmcs(unsigned int *num);
00210 extern pfm_err_t pfm_get_num_counters(unsigned int *num);
00211 
00212 extern pfm_err_t pfm_get_hw_counter_width(unsigned int *width);
00213 extern pfm_err_t pfm_get_version(unsigned int *version);
00214 extern char *pfm_strerror(int code);
00215 extern pfm_err_t pfm_get_cycle_event(pfmlib_event_t *e);
00216 extern pfm_err_t pfm_get_inst_retired_event(pfmlib_event_t *e);
00217 
00218 /*
00219  * Supported PMU family
00220  */
00221 #define PFMLIB_NO_PMU                   -1      /* PMU unused (forced) */
00222 #define PFMLIB_UNKNOWN_PMU              0       /* type not yet known (dynamic) */
00223 #define PFMLIB_GEN_IA64_PMU             1       /* Intel IA-64 architected PMU */
00224 #define PFMLIB_ITANIUM_PMU              2       /* Intel Itanium   */
00225 #define PFMLIB_ITANIUM2_PMU             3       /* Intel Itanium 2 */
00226 #define PFMLIB_MONTECITO_PMU            4       /* Intel Dual-Core Itanium 2 9000 */
00227 #define PFMLIB_AMD64_PMU                16      /* AMD AMD64 (K7, K8, Fam 10h) */
00228 #define PFMLIB_GEN_IA32_PMU             63      /* Intel architectural PMU for X86 */
00229 #define PFMLIB_I386_P6_PMU              32      /* Intel PIII (P6 core) */
00230 #define PFMLIB_PENTIUM4_PMU             33      /* Intel Pentium4/Xeon/EM64T */
00231 #define PFMLIB_COREDUO_PMU              34      /* Intel Core Duo/Core Solo */
00232 #define PFMLIB_I386_PM_PMU              35      /* Intel Pentium M */
00233 #define PFMLIB_CORE_PMU                 36      /* obsolete, use PFMLIB_INTEL_CORE_PMU */
00234 #define PFMLIB_INTEL_CORE_PMU           36      /* Intel Core */
00235 #define PFMLIB_INTEL_PPRO_PMU           37      /* Intel Pentium Pro */
00236 #define PFMLIB_INTEL_PII_PMU            38      /* Intel Pentium II */
00237 #define PFMLIB_INTEL_ATOM_PMU           39      /* Intel Atom */
00238 #define PFMLIB_INTEL_NHM_PMU            40      /* Intel Nehalem */
00239 #define PFMLIB_INTEL_WSM_PMU            41      /* Intel Westmere */
00240 
00241 #define PFMLIB_MIPS_20KC_PMU            64      /* MIPS 20KC */
00242 #define PFMLIB_MIPS_24K_PMU             65      /* MIPS 24K */
00243 #define PFMLIB_MIPS_25KF_PMU            66      /* MIPS 25KF */
00244 #define PFMLIB_MIPS_34K_PMU             67      /* MIPS 34K */
00245 #define PFMLIB_MIPS_5KC_PMU             68      /* MIPS 5KC */
00246 #define PFMLIB_MIPS_74K_PMU             69      /* MIPS 74K */
00247 #define PFMLIB_MIPS_R10000_PMU          70      /* MIPS R10000 */
00248 #define PFMLIB_MIPS_R12000_PMU          71      /* MIPS R12000 */
00249 #define PFMLIB_MIPS_RM7000_PMU          72      /* MIPS RM7000 */
00250 #define PFMLIB_MIPS_RM9000_PMU          73      /* MIPS RM9000 */
00251 #define PFMLIB_MIPS_SB1_PMU             74      /* MIPS SB1/SB1A */
00252 #define PFMLIB_MIPS_VR5432_PMU          75      /* MIPS VR5432 */
00253 #define PFMLIB_MIPS_VR5500_PMU          76      /* MIPS VR5500 */
00254 #define PFMLIB_MIPS_ICE9A_PMU           77      /* SiCortex ICE9A */
00255 #define PFMLIB_MIPS_ICE9B_PMU           78      /* SiCortex ICE9B */
00256 
00257 #define PFMLIB_POWERPC_PMU              90      /* POWERPC */
00258 
00259 #define PFMLIB_CRAYX2_PMU               96      /* Cray X2 */
00260 
00261 #define PFMLIB_CELL_PMU                 100     /* CELL */
00262 
00263 #define PFMLIB_PPC970_PMU               110     /* IBM PowerPC 970(FX,GX) */
00264 #define PFMLIB_PPC970MP_PMU             111     /* IBM PowerPC 970MP */     
00265 #define PFMLIB_POWER3_PMU               112     /* IBM POWER3 */
00266 #define PFMLIB_POWER4_PMU               113     /* IBM POWER4 */
00267 #define PFMLIB_POWER5_PMU               114     /* IBM POWER5 */
00268 #define PFMLIB_POWER5p_PMU              115     /* IBM POWER5+ */
00269 #define PFMLIB_POWER6_PMU               116     /* IBM POWER6 */
00270 #define PFMLIB_POWER7_PMU               117     /* IBM POWER7 */
00271 
00272 #define PFMLIB_SPARC_ULTRA12_PMU        130     /* UltraSPARC I, II, IIi, and IIe */
00273 #define PFMLIB_SPARC_ULTRA3_PMU         131     /* UltraSPARC III */
00274 #define PFMLIB_SPARC_ULTRA3I_PMU        132     /* UltraSPARC IIIi and IIIi+ */
00275 #define PFMLIB_SPARC_ULTRA3PLUS_PMU     133     /* UltraSPARC III+ and IV */
00276 #define PFMLIB_SPARC_ULTRA4PLUS_PMU     134     /* UltraSPARC IV+ */
00277 #define PFMLIB_SPARC_NIAGARA1_PMU       135     /* Niagara-1 */
00278 #define PFMLIB_SPARC_NIAGARA2_PMU       136     /* Niagara-2 */
00279 
00280 /*
00281  * pfmlib error codes
00282  */
00283 #define PFMLIB_SUCCESS            0     /* success */
00284 #define PFMLIB_ERR_NOTSUPP       -1     /* function not supported */
00285 #define PFMLIB_ERR_INVAL         -2     /* invalid parameters */
00286 #define PFMLIB_ERR_NOINIT        -3     /* library was not initialized */
00287 #define PFMLIB_ERR_NOTFOUND      -4     /* event not found */
00288 #define PFMLIB_ERR_NOASSIGN      -5     /* cannot assign events to counters */
00289 #define PFMLIB_ERR_FULL          -6     /* buffer is full or too small */
00290 #define PFMLIB_ERR_EVTMANY       -7     /* event used more than once */
00291 #define PFMLIB_ERR_MAGIC         -8     /* invalid library magic number */
00292 #define PFMLIB_ERR_FEATCOMB      -9     /* invalid combination of features */
00293 #define PFMLIB_ERR_EVTSET       -10     /* incompatible event sets */
00294 #define PFMLIB_ERR_EVTINCOMP    -11     /* incompatible event combination */
00295 #define PFMLIB_ERR_TOOMANY      -12     /* too many events or unit masks */
00296 
00297 #define PFMLIB_ERR_IRRTOOBIG    -13     /* code range too big */
00298 #define PFMLIB_ERR_IRREMPTY     -14     /* empty code range */
00299 #define PFMLIB_ERR_IRRINVAL     -15     /* invalid code range */
00300 #define PFMLIB_ERR_IRRTOOMANY   -16     /* too many code ranges */
00301 #define PFMLIB_ERR_DRRINVAL     -17     /* invalid data range */
00302 #define PFMLIB_ERR_DRRTOOMANY   -18     /* too many data ranges */
00303 #define PFMLIB_ERR_BADHOST      -19     /* not supported by host CPU */
00304 #define PFMLIB_ERR_IRRALIGN     -20     /* bad alignment for code range */
00305 #define PFMLIB_ERR_IRRFLAGS     -21     /* code range missing flags */
00306 #define PFMLIB_ERR_UMASK        -22     /* invalid or missing unit mask */
00307 #define PFMLIB_ERR_NOMEM        -23     /* out of memory */
00308 
00309 #define __PFMLIB_REGMASK_EL(g)          ((g)/__PFMLIB_REG_BV_BITS)
00310 #define __PFMLIB_REGMASK_MASK(g)        (((pfmlib_regmask_bits_t)1) << ((g) % __PFMLIB_REG_BV_BITS))
00311 
00312 static inline int
00313 pfm_regmask_isset(pfmlib_regmask_t *h, unsigned int b)
00314 {
00315         if (b >= PFMLIB_REG_MAX)
00316                 return 0;
00317         return (h->bits[__PFMLIB_REGMASK_EL(b)] & __PFMLIB_REGMASK_MASK(b)) != 0;
00318 }
00319 
00320 static inline int
00321 pfm_regmask_set(pfmlib_regmask_t *h, unsigned int b)
00322 {
00323         if (b >= PFMLIB_REG_MAX)
00324                 return PFMLIB_ERR_INVAL;
00325 
00326         h->bits[__PFMLIB_REGMASK_EL(b)] |=  __PFMLIB_REGMASK_MASK(b);
00327 
00328         return PFMLIB_SUCCESS;
00329 }
00330 
00331 static inline int
00332 pfm_regmask_clr(pfmlib_regmask_t *h, unsigned int b)
00333 {
00334         if (h == NULL || b >= PFMLIB_REG_MAX)
00335                 return PFMLIB_ERR_INVAL;
00336 
00337         h->bits[__PFMLIB_REGMASK_EL(b)] &= ~ __PFMLIB_REGMASK_MASK(b);
00338 
00339         return PFMLIB_SUCCESS;
00340 }
00341 
00342 static inline int
00343 pfm_regmask_weight(pfmlib_regmask_t *h, unsigned int *w)
00344 {
00345         unsigned int pos;
00346         unsigned int weight = 0;
00347 
00348         if (h == NULL || w == NULL)
00349                 return PFMLIB_ERR_INVAL;
00350 
00351         for (pos = 0; pos < PFMLIB_REG_BV; pos++) {
00352                 weight += (unsigned int)pfmlib_popcnt(h->bits[pos]);
00353         }
00354         *w = weight;
00355         return PFMLIB_SUCCESS;
00356 }
00357 
00358 static inline int
00359 pfm_regmask_eq(pfmlib_regmask_t *h1, pfmlib_regmask_t *h2)
00360 {
00361         unsigned int pos;
00362 
00363         if (h1 == NULL || h2 == NULL)
00364                 return 0;
00365 
00366         for (pos = 0; pos < PFMLIB_REG_BV; pos++) {
00367                 if (h1->bits[pos] != h2->bits[pos]) return 0;
00368         }
00369         return 1;
00370 }
00371 
00372 static inline int
00373 pfm_regmask_and(pfmlib_regmask_t *dst, pfmlib_regmask_t *h1, pfmlib_regmask_t *h2)
00374 {
00375         unsigned int pos;
00376         if (dst == NULL || h1 == NULL || h2 == NULL)
00377                 return PFMLIB_ERR_INVAL;
00378 
00379         for (pos = 0; pos < PFMLIB_REG_BV; pos++) {
00380                 dst->bits[pos] = h1->bits[pos] & h2->bits[pos];
00381         }
00382         return PFMLIB_SUCCESS;
00383 }
00384 
00385 static inline int
00386 pfm_regmask_andnot(pfmlib_regmask_t *dst, pfmlib_regmask_t *h1, pfmlib_regmask_t *h2)
00387 {
00388         unsigned int pos;
00389         if (dst == NULL || h1 == NULL || h2 == NULL)
00390                 return PFMLIB_ERR_INVAL;
00391 
00392         for (pos = 0; pos < PFMLIB_REG_BV; pos++) {
00393                 dst->bits[pos] = h1->bits[pos] & ~h2->bits[pos];
00394         }
00395         return PFMLIB_SUCCESS;
00396 }
00397 
00398 static inline int
00399 pfm_regmask_or(pfmlib_regmask_t *dst, pfmlib_regmask_t *h1, pfmlib_regmask_t *h2)
00400 {
00401         unsigned int pos;
00402         if (dst == NULL || h1 == NULL || h2 == NULL)
00403                 return PFMLIB_ERR_INVAL;
00404 
00405         for (pos = 0; pos < PFMLIB_REG_BV; pos++) {
00406                 dst->bits[pos] = h1->bits[pos] | h2->bits[pos];
00407         }
00408         return PFMLIB_SUCCESS;
00409 }
00410 
00411 static inline int
00412 pfm_regmask_copy(pfmlib_regmask_t *dst, pfmlib_regmask_t *src)
00413 {
00414         unsigned int pos;
00415         if (dst == NULL || src == NULL)
00416                 return PFMLIB_ERR_INVAL;
00417 
00418         for (pos = 0; pos < PFMLIB_REG_BV; pos++) {
00419                 dst->bits[pos] = src->bits[pos];
00420         }
00421         return PFMLIB_SUCCESS;
00422 }
00423 static inline int
00424 pfm_regmask_not(pfmlib_regmask_t *dst)
00425 {
00426         unsigned int pos;
00427         if (dst == NULL)
00428                 return PFMLIB_ERR_INVAL;
00429 
00430         for (pos = 0; pos < PFMLIB_REG_BV; pos++) {
00431                 dst->bits[pos] = ~dst->bits[pos];
00432         }
00433         return PFMLIB_SUCCESS;
00434 }
00435 
00436 #ifdef __cplusplus /* extern C */
00437 }
00438 #endif
00439 
00440 #endif /* __PFMLIB_H__ */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Mon Sep 17 2012 13:49:35 for Gaudi Framework, version v23r4 by Doxygen version 1.7.2 written by Dimitri van Heesch, © 1997-2004