darshan-common.h 9.38 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * Copyright (C) 2015 University of Chicago.
 * See COPYRIGHT notice in top-level directory.
 *
 */

#ifndef __DARSHAN_COMMON_H
#define __DARSHAN_COMMON_H

/* increment a timer counter, making sure not to account for overlap
 * with previous operations
 *
13 14 15 16
 * NOTE: __timer is the corresponding timer counter variable, __tm1 is
 * the start timestamp of the operation, __tm2 is the end timestamp of
 * the operation, and __last is the timestamp of the end of the previous
 * I/O operation (which we don't want to overlap with).
17
 */
18
#define DARSHAN_TIMER_INC_NO_OVERLAP(__timer, __tm1, __tm2, __last) do{ \
19 20
    if (__tm1 == 0.0 || __tm2 == 0.0) \
        break; \
21
    if(__tm1 > __last) \
22
        __timer += (__tm2 - __tm1); \
23
    else \
24
        __timer += (__tm2 - __last); \
25 26 27 28 29 30 31 32
    if(__tm2 > __last) \
        __last = __tm2; \
} while(0)

/* increment histogram bucket depending on the given __value
 *
 * NOTE: This macro can be used to build a histogram of access
 * sizes, offsets, etc. It assumes a 10-bucket histogram, with
33
 * __bucket_base_p pointing to the first counter in the sequence
34 35 36 37 38 39 40 41 42 43 44 45 46
 * of buckets (i.e., the smallest bucket). The size ranges of each
 * bucket are:
 *      * 0 - 100 bytes
 *      * 100 - 1 KiB
 *      * 1 KiB - 10 KiB
 *      * 10 KiB - 100 KiB
 *      * 100 KiB - 1 MiB
 *      * 1 MiB - 4 MiB
 *      * 4 MiB - 10 MiB
 *      * 10 MiB - 100 MiB
 *      * 100 MiB - 1 GiB
 *      * 1 GiB+
 */
47
#define DARSHAN_BUCKET_INC(__bucket_base_p, __value) do {\
48
    if(__value < 101) \
49
        *(__bucket_base_p) += 1; \
50
    else if(__value < 1025) \
51
        *(__bucket_base_p + 1) += 1; \
52
    else if(__value < 10241) \
53
        *(__bucket_base_p + 2) += 1; \
54
    else if(__value < 102401) \
55
        *(__bucket_base_p + 3) += 1; \
56
    else if(__value < 1048577) \
57
        *(__bucket_base_p + 4) += 1; \
58
    else if(__value < 4194305) \
59
        *(__bucket_base_p + 5) += 1; \
60
    else if(__value < 10485761) \
61
        *(__bucket_base_p + 6) += 1; \
62
    else if(__value < 104857601) \
63
        *(__bucket_base_p + 7) += 1; \
64
    else if(__value < 1073741825) \
65
        *(__bucket_base_p + 8) += 1; \
66
    else \
67
        *(__bucket_base_p + 9) += 1; \
68 69
} while(0)

70
/* potentially set or increment a common value counter, depending on the __count
71 72 73 74
 * for the given __value. This macro ensures common values are stored first in
 * decreasing order of their total count, and second by decreasing order of
 * their value.

75 76 77 78 79 80
 *
 * NOTE: This macro is hardcoded to expect that Darshan will only track the 4
 * most common (i.e., frequently occuring) values. __val_p is a pointer to the
 * base of the value counters (i.e., the first of 4 contiguous common value
 * counters) and __cnt_p is a pointer to the base of the count counters (i.e.
 * the first of 4 contiguous common count counters). It is assumed your counters
81 82
 * are stored as int64_t types. __add_flag is set if the given count should be
 * added to the common access counter, rather than just incrementing it.
83
 */
84
#define DARSHAN_COMMON_VAL_COUNTER_INC(__val_p, __cnt_p, __value, __count, __add_flag) do {\
85
    int i; \
86 87 88 89
    int inc_count, total_count; \
    int64_t tmp_val[4] = {0}; \
    int64_t tmp_cnt[4] = {0}; \
    int tmp_ndx = 0; \
90
    if(__value == 0) break; \
91
    if(__add_flag) \
92 93 94
        inc_count = 1; \
    else \
        inc_count = __count; \
95 96
    for(i=0; i<4; i++) { \
        if(*(__val_p + i) == __value) { \
97
            total_count = *(__cnt_p + i) + inc_count; \
98 99
            break; \
        } \
100 101 102 103 104 105 106 107 108 109 110
    } \
    if(i == 4) total_count = __count; \
    /* first, copy over any counters that should be sorted above this one \
     * (counters with higher counts or equal counts and larger values) \
     */ \
    for(i=0;i < 4; i++) { \
        if((*(__cnt_p + i) > total_count) || \
           ((*(__cnt_p + i) == total_count) && (*(__val_p + i) > __value))) { \
            tmp_val[tmp_ndx] = *(__val_p + i); \
            tmp_cnt[tmp_ndx] = *(__cnt_p + i); \
            tmp_ndx++; \
111
        } \
112
        else break; \
113
    } \
114 115 116 117 118 119 120 121 122 123 124 125 126
    if(tmp_ndx == 4) break; /* all done, updated counter is not added */ \
    /* next, add the updated counter */ \
    tmp_val[tmp_ndx] = __value; \
    tmp_cnt[tmp_ndx] = total_count; \
    tmp_ndx++; \
    /* last, copy over any remaining counters to make sure we have 4 sets total */ \
    while(tmp_ndx != 4) { \
        if(*(__val_p + i) != __value) { \
            tmp_val[tmp_ndx] = *(__val_p + i); \
            tmp_cnt[tmp_ndx] = *(__cnt_p + i); \
            tmp_ndx++; \
        } \
        i++; \
127
    } \
128 129
    memcpy(__val_p, tmp_val, 4*sizeof(int64_t)); \
    memcpy(__cnt_p, tmp_cnt, 4*sizeof(int64_t)); \
130 131
} while(0)

132
/* maximum number of common values that darshan will track per file at runtime */
133 134 135 136 137 138 139
#define DARSHAN_COMMON_VAL_MAX_RUNTIME_COUNT 32
struct darshan_common_val_counter
{
    int64_t val;
    int freq;
};

140 141 142 143 144 145 146
/* i/o type (read or write) */
enum darshan_io_type
{
    DARSHAN_IO_READ = 1,
    DARSHAN_IO_WRITE = 2,
};

147 148 149 150 151 152 153 154
/* struct used for calculating variances */
struct darshan_variance_dt
{
    double n;
    double T;
    double S;
};

155 156 157 158
/***********************************************
* darshan-common functions for darshan modules *
***********************************************/

159 160 161 162 163 164 165 166
/* darshan_lookup_record_ref()
 *
 * Lookup a record reference pointer using the given 'handle'.
 * 'handle_sz' is the size of the handle structure, and 'hash_head'
 * is the pointer to the hash table to search.
 * If the handle is found, the corresponding record reference pointer
 * is returned, otherwise NULL is returned.
 */
167 168 169 170 171
void *darshan_lookup_record_ref(
    void *hash_head,
    void *handle,
    size_t handle_sz);

172 173 174 175 176 177 178 179
/* darshan_add_record_ref()
 *
 * Add the given record reference pointer, 'rec_ref_p' to the hash
 * table whose address is stored in the 'hash_head_p' pointer. The
 * hash is generated from the given 'handle', with size 'handle_sz'.
 * If the record reference is successfully added, 1 is returned,
 * otherwise, 0 is returned.
 */
180
int darshan_add_record_ref(
181
    void **hash_head_p,
182 183 184 185
    void *handle,
    size_t handle_sz,
    void *rec_ref_p);

186 187 188 189 190 191 192 193
/* darshan_delete_record_ref()
 *
 * Delete the record reference for the given 'handle', with size
 * 'handle_sz', from the hash table whose address is stored in
 * the 'hash_head_p' pointer.
 * On success deletion, the corresponding record reference pointer
 * is returned, otherwise NULL is returned.
 */
194
void *darshan_delete_record_ref(
195
    void **hash_head_p,
196 197 198
    void *handle,
    size_t handle_sz);

199 200 201 202 203 204
/* darshan_clear_record_refs()
 *
 * Clear all record references from the hash table stored in the
 * 'hash_head_p' pointer. If 'free_flag' is set, the corresponding
 * record_reference_pointer is also freed.
 */
205
void darshan_clear_record_refs(
206
    void **hash_head_p,    
207 208
    int free_flag);

209 210 211 212 213 214 215
/* darshan_iter_record_ref()
 *
 * Iterate each record reference stored in the hash table pointed
 * to by 'hash_head' and perform the given action 'iter_action'. 
 * The action function takes a single pointer which points to the
 * corresponding record reference pointer.
 */
216 217 218 219
void darshan_iter_record_refs(
    void *hash_head,
    void (*iter_action)(void *));

220 221 222 223 224 225 226
/* darshan_clean_file_path()
 *
 * Allocate a new string that contains a new cleaned-up version of
 * the file path given in 'path' argument. Converts relative paths
 * to absolute paths and filters out some potential noise in the
 * path string.
 */
227
char* darshan_clean_file_path(
228
    const char *path);
229

230 231 232 233 234 235 236 237 238
/* darshan_record_sort()
 *
 * Sort the records in 'rec_buf' by descending rank to get all
 * shared records in a contiguous region at the end of the buffer.
 * Records are secondarily sorted by ascending record identifiers.
 * 'rec_count' is the number of records in the buffer, and 'rec_size'
 * is the size of the record structure.
 * NOTE: this function only works on fixed-length records.
 */
239 240 241 242 243
void darshan_record_sort(
    void *rec_buf,
    int rec_count,
    int rec_size);

244 245 246 247 248 249 250 251
/* darshan_common_val_counter()
 *
 * Potentially increment an existing common value counter or allocate
 * a new one to keep track of commonly occuring values. Example use
 * cases would be to track the most frequent access sizes or strides
 * used by a specific module, for instance. 'common_val_root' is the
 * root pointer for the tree which stores common value info, 
 * 'common_val_count' is a pointer to the number of nodes in the 
252 253 254 255 256 257
 * tree (i.e., the number of allocated common value counters), 'val'
 * is the new value to attempt to add, 'val_p' is a pointer to the
 * base counter (i.e., the first) of the common values (which are
 * assumed to be 4 total and contiguous in memory), and 'cnt_p' is
 * a pointer to the base counter of the common counts (which are
 * again expected to be contiguous in memory).
258 259
 */
void darshan_common_val_counter(
260 261 262 263 264
    void **common_val_root,
    int *common_val_count,
    int64_t val,
    int64_t *val_p,
    int64_t *cnt_p);
265

266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
/* darshan_variance_reduce()
 *
 * MPI reduction operation to calculate variances on counters in
 * data records which are shared across all processes. This could
 * be used, for instance, to find the variance in I/O time or total
 * bytes moved for a given data record. This function needs to be
 * passed to MPI_Op_create to obtain a corresponding MPI operation
 * which can be used to complete the reduction.  For more details,
 * consult the documentation for MPI_Op_create. Example use cases
 * can be found in the POSIX and MPIIO modules.
 */
void darshan_variance_reduce(
    void *invec,
    void *inoutvec,
    int *len,
    MPI_Datatype *dt);

283
#endif /* __DARSHAN_COMMON_H */