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. πβ¨π¦
π¦ where this page comes from
- debian bookworm: libedac-dev 0.18+git12-gd98769e-1
- debian trixie: libedac-dev 0.18+git16-g8fdc1d4-2
- epel 10: libedac-devel 0.18-38.el10_0 Β· GPL-2.0-or-later
- epel 9: libedac-devel 0.18-29.el9 Β· GPL-2.0-or-later
- fedora 43: libedac-devel 0.18-43.fc43 Β· GPL-2.0-or-later
- fedora 44: libedac-devel 0.18-46.fc44 Β· GPL-2.0-or-later
- nixos 26.05: edac-utils-unstable 2023-01-30
- nixpkgs unstable: edac-utils 0.18-unstable-2023-01-30
- ubuntu jammy: libedac-dev 0.18+git12-gd98769e-1
- ubuntu noble: libedac-dev 0.18+git12-gd98769e-1build1
- ubuntu questing: libedac-dev 0.18+git16-g8fdc1d4-2
- ubuntu resolute: libedac-dev 0.18+git16-g8fdc1d4-3 Β· GPL-2.0-or-later
- ubuntu stonking: libedac-dev 0.18+git16-g8fdc1d4-3 Β· GPL-2.0-or-later
- Copyright (C) 2006-2007 The Regents of the University of California
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms