EDAC(3)

πŸ’– EDAC(3) β€” the libedac era πŸ’–

okay bestie, sit down, we're learning the libedac manual page β€” the EDAC error reporting library, straight out of the EDAC(3) chapter. no cap, this one's actually so useful. πŸ¦‹


✨ NAME ✨

libedac β€” the EDAC error reporting library. that's it, that's the name. πŸ’…


🌸 SYNOPSIS 🌸

first things first, you gotta pull it in:

#include <edac.h>

cc ... -ledac

and now the whole friend group, one by one:

edac_handle * edac_handle_create (void);

void edac_handle_destroy (edac_handle *edac);

int edac_handle_init (edac_handle *edac);

unsigned int edac_mc_count (edac_handle *edac);

int edac_handle_reset (edac_handle *edac);

int edac_error_totals (edac_handle *edac, struct edac_totals *totals);

edac_mc * edac_next_mc (edac_handle *edac);

int edac_mc_get_info (edac_mc *mc, struct edac_mc_info *info);

edac_mc *edac_next_mc_info (edac_handle *edac,
                            struct edac_mc_info *info);

int edac_mc_reset (struct edac_mc *mc);

edac_csrow * edac_next_csrow (struct edac_mc *mc);

int edac_csrow_get_info (edac_csrow *csrow,
                         struct edac_csrow_info *info);

edac_csrow * edac_next_csrow_info (edac_mc *mc,
                                   struct edac_csrow_info *info);

const char * edac_strerror (edac_handle *edac);

edac_for_each_mc_info (edac_handle *edac, edac_mc *mc,
                       struct edac_csrow_info *info)    { ... }

edac_for_each_csrow_info (edac_mc *mc, edac_csrow *csrow,
                          struct edac_csrow_info *info) { ... }

πŸ‘‘ DESCRIPTION πŸ‘‘

so here's the vibe: the libedac library gives you a very simple programming interface to all the info that in-kernel EDAC (Error Detection and Correction) drivers export over in sysfs. and the edac-util(8) utility? it uses libedac to report errors in a super user-friendly way from the command line. iconic behavior. ✨

for most systems, EDAC errors get recorded in sysfs on a per memory controller (MC) basis. memory controllers then get further subdivided by csrow and channel. libedac hands you a method to loop through multiple MCs and their corresponding csrows, grabbing info about each component from sysfs along the way. 🧚 and there's also a simple single call to snag the total error counts for a given machine. periodt.

to use libedac you first gotta open an edac_handle via the call edac_handle_create(). once the handle exists, sysfs data can be loaded into it with edac_handle_init(). then a final call to edac_handle_destroy() frees all memory and open files associated with the edac handle. cleanup queen. πŸ’…

edac_handle_create() will return NULL on failure to allocate memory. (memory said no 😭)

the edac_strerror function returns a descriptive string representation of the last error for the libedac handle edac. πŸ’¬

the edac_error_totals() function returns the total counts of memory and pci errors in the totals structure you pass to the function. the totals structure is of type edac_totals, which has the form:

struct edac_totals {
   unsigned int  ce_total;         /* Total corrected errors   */
   unsigned int  ue_total;         /* Total uncorrected errors */
   unsigned int  pci_parity_total; /* Total PCI Parity errors  */
};

πŸŽ€ MEMORY CONTROLLER INFORMATION πŸŽ€

systems may have one or more memory controllers (MCs) with EDAC information. the number of MCs detected by EDAC drivers can be queried with the edac_mc_count() function, while the edac_next_mc function returns a handle to the next memory controller in the libedac handle's internal list. this memory controller is represented by the opaque edac_mc type. πŸ‘» (opaque = mysterious = main character energy, honestly)

edac_next_mc returns NULL when there are no further memory controllers to return. so check this out β€” the following example code is another method to count all EDAC MCs (assuming the EDAC library handle edac has already been initialized):

int i = 0;
edac_mc *mc;
while ((mc = edac_next_mc (edac)))
    i++;
return (i);

to query info about an edac_mc, use the edac_mc_get_info function. it fills in the given info structure, which is of type edac_mc_info:

struct edac_mc_info {
    char           id[];           /* Id of memory controller */
    char           mc_name[];      /* Name of MC              */
    unsigned int   size_mb;        /* Amount of RAM in MB     */
    unsigned int   ce_count;       /* Corrected error count   */
    unsigned int   ce_noinfo_count;/* noinfo Corrected errors */
    unsigned int   ue_count;       /* Uncorrected error count */
    unsigned int   ue_noinfo_count;/* noinfo Uncorrected errors*/
};

the function edac_next_mc_info() can be used to loop through all EDAC memory controllers and obtain MC info in a single call. it's literally a combined edac_next_mc() and edac_mc_get_info(). two for one, bestie, we love a bundle deal. 🫢

the function edac_handle_reset() resets the internal memory controller iterator in the libedac handle. so a subsequent call to edac_next_mc() would return the first EDAC MC. rewind time. βͺ

a convenience macro, edac_for_each_mc_info(), is provided which defines a for loop that iterates through all memory controller objects for a given EDAC handle, returning the MC information in the info structure on each iteration. for example (assuming initialized libedac handle edac):

edac_mc *mc;
struct edac_mc_info info;
int count = 0;

edac_for_each_mc_info (edac, mc, info) {
    count++;
    printf ("MC info: id=%s name=%s\n", info.id, info.mc_name);
}

πŸ¦‹ CSROW INFORMATION πŸ¦‹

each EDAC memory controller may have one or more csrows associated with it. similar to the MC iterator functions described above, the edac_next_csrow() function lets libedac users loop through all csrows within a given MC. once the last csrow is reached, the function returns NULL. πŸšͺ (door's closed, no more csrows)

the edac_csrow_get_info() function returns information about edac_csrow in the edac_csrow_info structure, which has the contents:

struct edac_csrow_info {
    char          id[];      /* CSROW Identity (e.g. csrow0)  */
    unsigned int  size_mb;   /* CSROW size in MB              */
    unsigned int  ce_count;  /* Total corrected errors        */
    unsigned int  ue_count;  /* Total uncorrected errors      */
    struct edac_channel channel[EDAC_MAX_CHANNELS];
};

struct edac_channel {
    int           valid;            /* Is this channel valid */
    unsigned int  ce_count;         /* Corrected error count */
    int           dimm_label_valid; /* Is DIMM label valid?  */
    char          dimm_label[];     /* DIMM name             */
};

the edac_next_csrow_info() function is a combined version of edac_next_csrow() and edac_csrow_get_info() for convenience. ✨ again with the combos, we stan efficiency.

the edac_mc_reset() function is provided to reset the edac_mc internal csrow iterator. βͺ

a convenience macro, edac_for_each_csrow_info(), is provided which defines a for loop that iterates through all csrow objects in an EDAC memory controller, returning the csrow information in the info structure on each iteration. 🌈


πŸ”₯ EXAMPLES πŸ”₯

okay these are the fun part, let's go.

initialize libedac handle:

edac_handle *edac;

if (!(edac = edac_handle_create ())) {
    fprintf (stderr, "edac_handle_create: Out of memory!\n");
    exit (1);
}

if (edac_handle_init (edac) < 0) {
   fprintf (stderr, "Unable to get EDAC data: %s\n",
                    edac_strerror (edac));
   exit (1);
}

printf ("EDAC initialized with %d MCs\n", edac_mc_count (edac));

edac_handle_destroy (edac);

report all DIMM labels for MC:csrow:channel combinations:

edac_mc *mc;
edac_csrow *csrow;
struct edac_mc_info mci;
struct edac_csrow_info csi;

edac_for_each_mc_info (ctx->edac, mc, mci) {
    edac_for_each_csrow_info (mc, csrow, csi) {
        char *label[2] = { "unset", "unset" };

        if (csi.channel[0].dimm_label_valid)
            label[0] = csi.channel[0].dimm_label;
        if (csi.channel[1].dimm_label_valid)
            label[1] = csi.channel[1].dimm_label;

        printf ("%s:%s:ch0 = %s\n", mci.id, csi.id, label[0]);
        printf ("%s:%s:ch1 = %s\n", mci.id, csi.id, label[1]);
    }
}

πŸ’œ SEE ALSO πŸ’œ

edac-util(8), edac-ctl(8)

go read those next bestie, they're the sequel. πŸ’–


and that's the page!! πŸ’… this one came from the @META_ALIAS source, version date 2011-11-09, and it lives in section EDAC(3). you ate that, fr fr. πŸŽ€βœ¨πŸ¦‹