File: iostat.h

package info (click to toggle)
lizardfs 3.12.0+dfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 8,064 kB
  • sloc: cpp: 91,899; sh: 9,341; python: 3,878; ansic: 3,109; pascal: 128; makefile: 57
file content (141 lines) | stat: -rw-r--r-- 4,010 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
   Copyright 2017 Skytechnology sp. z o.o..

   This file is part of LizardFS.

   LizardFS is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, version 3.

   LizardFS is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with LizardFS  If not, see <http://www.gnu.org/licenses/>.

   Based on sysstat's
   iostat: report CPU and I/O statistics
   (C) 1998-2016 by Sebastien GODARD (sysstat <at> orange.fr)
 */

#include "common/platform.h"

#include <cassert>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <unordered_map>
#include <vector>

#include <sys/stat.h>
#include <sys/sysmacros.h>  // makedev
#include <sys/types.h>
#include <unistd.h>

#ifndef __linux__

class IoStat {
public:
	void resetPaths(const std::vector<std::string> &) {}
	uint8_t getLoadFactor() { return 0; }
};

#else
#include <cstdio>
#include <ctime>
#include <sys/vfs.h>

class IoStat {
protected:
	static const int kMaxLineLen = 1024;
	static const int kMaxNameLen = 1024;
	static const int kMaxPathLen = 4096;
	static const int kVariableCount = 14;
	static const constexpr char *kDiskstats = "/proc/diskstats";

	struct StatEntry {
		unsigned ticks;
		size_t size;
	};

	typedef std::unordered_map<dev_t, StatEntry> StatsMap;

public:
	void resetPaths(const std::vector<std::string> &paths) {
		prev_timestamp_ = 0;
		prev_load_factor_ = 0;
		for (auto &path : paths) {
			struct stat st;
			struct statfs stfs;
			int ret = ::stat(path.c_str(), &st);
			if (ret < 0) {
				// stat failed, ignore this directory
				continue;
			}
			ret = ::statfs(path.c_str(), &stfs);
			if (ret < 0) {
				continue;
			}
			stats_[st.st_dev] = {0, stfs.f_blocks};
		}
	}

	uint8_t getLoadFactor() {
		std::FILE *fp;
		char line[kMaxLineLen], dev_name[kMaxNameLen];
		int i;
		unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks;
		unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios;
		unsigned long wr_merges, rd_sec_or_wr_ios, wr_sec;
		unsigned int major, minor;

		if (stats_.size() == 0) {
			return 0;
		}
		if (prev_timestamp_ >= (unsigned long)std::time(nullptr)) {
			return prev_load_factor_;
		}
		if ((fp = fopen(kDiskstats, "r")) == nullptr) {
			return 0;
		}

		unsigned long long sum = 0;
		size_t total_size = 0;
		while (fgets(line, sizeof(line), fp) != nullptr) {
			// major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq
			i = sscanf(line, "%u %u %s %lu %lu %lu %lu %lu %lu %lu %u %u %u %u",
				&major, &minor, dev_name,
				&rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
				&wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks);

			auto it = stats_.find(makedev(major, minor));
			if (i == kVariableCount && it != stats_.end()) {
				StatEntry &entry = it->second;
				sum += (tot_ticks - entry.ticks) * entry.size;
				total_size += entry.size;
				entry.ticks = tot_ticks;
			}
		}

		unsigned long timestamp = (unsigned long)std::time(nullptr);
		unsigned long timestamp_diff = timestamp - prev_timestamp_;
		// mean of milliseconds spent on I/O divided by time difference in seconds
		// and divided again by 10 will give a mean percentage of I/O load for all used paths
		unsigned long divisor = total_size * timestamp_diff * 10;
		// sometimes factor can be greater than 100 because timestamp is set _after_
		// reading disk stats (better to overestimate a bit than underestimate).
		prev_load_factor_ = std::min(sum / (divisor ? divisor : 1), 100ULL);
		prev_timestamp_ = timestamp;
		fclose(fp);
		return prev_load_factor_;
	}

protected:
	unsigned long prev_timestamp_;
	unsigned long prev_load_factor_;
	StatsMap stats_;
};

#endif