From: Petr Tesarik Date: Mon Sep 8 17:33:38 2014 +0200 Subject: Take constant-size slabs into account for "kdump calibrate" References: bnc#879460 Patch-mainline: v0.8.16 Git-commit: 3a7c9b3a02893ab9ac39e23cae5ead9e42716927 Git-commit: 8c0a42e80a89100addc09d584253f1c8accde500 Some slabs do not depend on available memory or system utilization. Their size can be taken directly from the running kernel. Note that the size of the ACPI slab cache may vary widely across machines (e.g. mine has only a few hundred kilobytes, while another one I saw had over 10 megabytes). Signed-off-by: Petr Tesarik --- kdumptool/calibrate.cc | 215 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) --- a/kdumptool/calibrate.cc +++ b/kdumptool/calibrate.cc @@ -448,6 +448,201 @@ unsigned long Framebuffers::size(void) c } //}}} +//{{{ SlabInfo ----------------------------------------------------------------- + +class SlabInfo { + + public: + /** + * Initialize a new SlabInfo object. + * + * @param[in] line Line from /proc/slabinfo + */ + SlabInfo(const KString &line); + + protected: + bool m_comment; + KString m_name; + unsigned long m_active_objs; + unsigned long m_num_objs; + unsigned long m_obj_size; + unsigned long m_obj_per_slab; + unsigned long m_pages_per_slab; + unsigned long m_active_slabs; + unsigned long m_num_slabs; + + public: + bool isComment(void) const + throw () + { return m_comment; } + + const KString &name(void) const + throw () + { return m_name; } + + unsigned long activeObjs(void) const + throw () + { return m_active_objs; } + + unsigned long numObjs(void) const + throw () + { return m_num_objs; } + + unsigned long objSize(void) const + throw () + { return m_obj_size; } + + unsigned long objPerSlab(void) const + throw () + { return m_obj_per_slab; } + + unsigned long pagesPerSlab(void) const + throw () + { return m_pages_per_slab; } + + unsigned long activeSlabs(void) const + throw () + { return m_active_slabs; } + + unsigned long numSlabs(void) const + throw () + { return m_num_slabs; } +}; + +// ----------------------------------------------------------------------------- +SlabInfo::SlabInfo(const KString &line) +{ + static const char slabdata_mark[] = " : slabdata "; + + std::istringstream ss(line); + ss >> m_name; + if (!ss) + throw KError("Invalid slabinfo line: " + line); + + if (m_name[0] == '#') { + m_comment = true; + return; + } + m_comment = false; + + ss >> m_active_objs >> m_num_objs >> m_obj_size + >> m_obj_per_slab >> m_pages_per_slab; + if (!ss) + throw KError("Invalid slabinfo line: " + line); + + size_t sdpos = line.find(slabdata_mark, ss.tellg()); + if (sdpos == KString::npos) + throw KError("Invalid slabinfo line: " + line); + + ss.seekg(sdpos + sizeof(slabdata_mark) - 1, ss.beg); + ss >> m_active_slabs >> m_num_slabs; + if (!ss) + throw KError("Invalid slabinfo line: " + line); +} + +//}}} +//{{{ SlabInfos ---------------------------------------------------------------- + +// Taken from procps: +#define SLABINFO_LINE_LEN 2048 +#define SLABINFO_VER_LEN 100 + +class SlabInfos { + + public: + typedef std::map Map; + + /** + * Initialize a new SlabInfos object. + * + * @param[in] procdir Mount point for procfs + */ + SlabInfos(const char *procdir = "/proc") + throw () + : m_path(FilePath(procdir).appendPath("slabinfo")) + {} + + ~SlabInfos() + { destroyInfo(); } + + protected: + /** + * Path to the slabinfo file + */ + const FilePath m_path; + + /** + * SlabInfo for each slab + */ + Map m_info; + + private: + /** + * Destroy SlabInfo objects in m_info. + */ + void destroyInfo(void) + throw(); + + public: + /** + * Read the information about each slab. + */ + const Map& getInfo(void); +}; + +// ----------------------------------------------------------------------------- +void SlabInfos::destroyInfo(void) + throw() +{ + Map::iterator it; + for (it = m_info.begin(); it != m_info.end(); ++it) + delete it->second; + m_info.clear(); +} + +// ----------------------------------------------------------------------------- +const SlabInfos::Map& SlabInfos::getInfo(void) +{ + static const char verhdr[] = "slabinfo - version: "; + char buf[SLABINFO_VER_LEN], *p, *end; + unsigned long major, minor; + + std::ifstream f(m_path.c_str()); + if (!f) + throw KError(m_path + ": Open failed"); + f.getline(buf, sizeof buf); + if (f.bad()) + throw KError(m_path + ": Read failed"); + else if (!f || strncmp(buf, verhdr, sizeof(verhdr)-1)) + throw KError(m_path + ": Invalid version"); + p = buf + sizeof(verhdr) - 1; + + major = strtoul(p, &end, 10); + if (end == p || *end != '.') + throw KError(m_path + ": Invalid version"); + p = end + 1; + minor = strtoul(p, &end, 10); + if (end == p || *end != '\0') + throw KError(m_path + ": Invalid version"); + Debug::debug()->dbg("Found slabinfo version %lu.%lu", major, minor); + + if (major != 2) + throw KError(m_path + ": Unsupported slabinfo version"); + + char line[SLABINFO_LINE_LEN]; + while(f.getline(line, SLABINFO_LINE_LEN)) { + SlabInfo *si = new SlabInfo(line); + if (si->isComment()) { + delete si; + continue; + } + m_info[si->name()] = si; + } + + return m_info; +} + +//}}} //{{{ Calibrate ---------------------------------------------------------------- // ----------------------------------------------------------------------------- @@ -498,6 +693,26 @@ void Calibrate::execute() required += DEF_FRAMEBUFFER_KB; } + // Add space for constant slabs + try { + SlabInfos slab; + SlabInfos::Map info = slab.getInfo(); + SlabInfos::Map::iterator it; + for (it = info.begin(); it != info.end(); ++it) { + if (it->first.startsWith("Acpi-") || + it->first.startsWith("ftrace_") ) { + unsigned long slabsize = it->second->numSlabs() * + it->second->pagesPerSlab() * pagesize / 1024; + required += slabsize; + + Debug::debug()->dbg("Adding %ld KiB for %s slab cache", + slabsize, it->second->name().c_str()); + } + } + } catch (KError e) { + Debug::debug()->dbg("Cannot get slab sizes: %s", e.what()); + } + // Add memory based on CPU count unsigned long cpus; if (CAN_REDUCE_CPUS) {