← Documents Documentation/admin-guide/iostats.rst GitHub 원문 ↗

Linux 6.18.37 · Administration / Block I/O

I/O statistics fields

`/proc/diskstats`와 sysfs의 17개 I/O 통계 필드, 파티션 집계 차이, 동시성 오차와 시간 단위를 설명합니다.

Source pathDocumentation/admin-guide/iostats.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

통계 인터페이스

iostats.rst:1-41

두 통계 파일의 형식, 장치별 접근 비용과 누적 카운터 초기화 조건을 설명합니다.

필드 정의

iostats.rst:42-125

read·write·discard·flush와 I/O 대기 시간 관련 필드 17개를 정리합니다.

파티션 통계

iostats.rst:126-170

커널 세대별 디스크·파티션 집계 시점과 병합으로 생기는 차이를 설명합니다.

운영 참고

iostats.rst:171-187

sysfs 마운트와 `/proc/stat` 통계 위치의 역사적 차이를 안내합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 =====================
2 I/O statistics fields
3 =====================
4
5 The kernel exposes disk statistics via ``/proc/diskstats`` and
6 ``/sys/block/<device>/stat``. These stats are usually accessed via tools
7 such as ``sar`` and ``iostat``.
8
9 Here are examples using a disk with two partitions::
10
11 /proc/diskstats:
12 259 0 nvme0n1 255999 814 12369153 47919 996852 81 36123024 425995 0 301795 580470 0 0 0 0 60602 106555
13 259 1 nvme0n1p1 492 813 17572 96 848 81 108288 210 0 76 307 0 0 0 0 0 0
14 259 2 nvme0n1p2 255401 1 12343477 47799 996004 0 36014736 425784 0 344336 473584 0 0 0 0 0 0
15
16 /sys/block/nvme0n1/stat:
17 255999 814 12369153 47919 996858 81 36123056 426009 0 301809 580491 0 0 0 0 60605 106562
18
19 /sys/block/nvme0n1/nvme0n1p1/stat:
20 492 813 17572 96 848 81 108288 210 0 76 307 0 0 0 0 0 0
21
22 Both files contain the same 17 statistics. ``/sys/block/<device>/stat``
23 contains the fields for ``<device>``. In ``/proc/diskstats`` the fields
24 are prefixed with the major and minor device numbers and the device
25 name. In the example above, the first stat value for ``nvme0n1`` is
26 255999 in both files.
27
28 The sysfs ``stat`` file is efficient for monitoring a small, known set
29 of disks. If you're tracking a large number of devices,
30 ``/proc/diskstats`` is often the better choice since it avoids the
31 overhead of opening and closing multiple files for each snapshot.
32
33 All fields are cumulative, monotonic counters, except for field 9, which
34 resets to zero as I/Os complete. The remaining fields reset at boot, on
35 device reattachment or reinitialization, or when the underlying counter
36 overflows. Applications reading these counters should detect and handle
37 resets when comparing stat snapshots.
38
39 Each set of stats only applies to the indicated device; if you want
40 system-wide stats you'll have to find all the devices and sum them all up.
41
42 Field 1 -- # of reads completed (unsigned long)
43 This is the total number of reads completed successfully.
44
45 Field 2 -- # of reads merged, field 6 -- # of writes merged (unsigned long)
46 Reads and writes which are adjacent to each other may be merged for
47 efficiency. Thus two 4K reads may become one 8K read before it is
48 ultimately handed to the disk, and so it will be counted (and queued)
49 as only one I/O. This field lets you know how often this was done.
50
51 Field 3 -- # of sectors read (unsigned long)
52 This is the total number of sectors read successfully.
53
54 Field 4 -- # of milliseconds spent reading (unsigned int)
55 This is the total number of milliseconds spent by all reads (as
56 measured from blk_mq_alloc_request() to __blk_mq_end_request()).
57
58 Field 5 -- # of writes completed (unsigned long)
59 This is the total number of writes completed successfully.
60
61 Field 6 -- # of writes merged (unsigned long)
62 See the description of field 2.
63
64 Field 7 -- # of sectors written (unsigned long)
65 This is the total number of sectors written successfully.
66
67 Field 8 -- # of milliseconds spent writing (unsigned int)
68 This is the total number of milliseconds spent by all writes (as
69 measured from blk_mq_alloc_request() to __blk_mq_end_request()).
70
71 Field 9 -- # of I/Os currently in progress (unsigned int)
72 The only field that should go to zero. Incremented as requests are
73 given to appropriate struct request_queue and decremented as they finish.
74
75 Field 10 -- # of milliseconds spent doing I/Os (unsigned int)
76 This field increases so long as field 9 is nonzero.
77
78 Since 5.0 this field counts jiffies when at least one request was
79 started or completed. If request runs more than 2 jiffies then some
80 I/O time might be not accounted in case of concurrent requests.
81
82 Field 11 -- weighted # of milliseconds spent doing I/Os (unsigned int)
83 This field is incremented at each I/O start, I/O completion, I/O
84 merge, or read of these stats by the number of I/Os in progress
85 (field 9) times the number of milliseconds spent doing I/O since the
86 last update of this field. This can provide an easy measure of both
87 I/O completion time and the backlog that may be accumulating.
88
89 Field 12 -- # of discards completed (unsigned long)
90 This is the total number of discards completed successfully.
91
92 Field 13 -- # of discards merged (unsigned long)
93 See the description of field 2
94
95 Field 14 -- # of sectors discarded (unsigned long)
96 This is the total number of sectors discarded successfully.
97
98 Field 15 -- # of milliseconds spent discarding (unsigned int)
99 This is the total number of milliseconds spent by all discards (as
100 measured from blk_mq_alloc_request() to __blk_mq_end_request()).
101
102 Field 16 -- # of flush requests completed
103 This is the total number of flush requests completed successfully.
104
105 Block layer combines flush requests and executes at most one at a time.
106 This counts flush requests executed by disk. Not tracked for partitions.
107
108 Field 17 -- # of milliseconds spent flushing
109 This is the total number of milliseconds spent by all flush requests.
110
111 To avoid introducing performance bottlenecks, no locks are held while
112 modifying these counters. This implies that minor inaccuracies may be
113 introduced when changes collide, so (for instance) adding up all the
114 read I/Os issued per partition should equal those made to the disks ...
115 but due to the lack of locking it may only be very close.
116
117 In 2.6+, there are counters for each CPU, which make the lack of locking
118 almost a non-issue. When the statistics are read, the per-CPU counters
119 are summed (possibly overflowing the unsigned long variable they are
120 summed to) and the result given to the user. There is no convenient
121 user interface for accessing the per-CPU counters themselves.
122
123 Since 4.19 request times are measured with nanoseconds precision and
124 truncated to milliseconds before showing in this interface.
125
126 Disks vs Partitions
127 -------------------
128
129 There were significant changes between 2.4 and 2.6+ in the I/O subsystem.
130 As a result, some statistic information disappeared. The translation from
131 a disk address relative to a partition to the disk address relative to
132 the host disk happens much earlier. All merges and timings now happen
133 at the disk level rather than at both the disk and partition level as
134 in 2.4. Consequently, you'll see a different statistics output on 2.6+ for
135 partitions from that for disks. There are only *four* fields available
136 for partitions on 2.6+ machines. This is reflected in the examples above.
137
138 Field 1 -- # of reads issued
139 This is the total number of reads issued to this partition.
140
141 Field 2 -- # of sectors read
142 This is the total number of sectors requested to be read from this
143 partition.
144
145 Field 3 -- # of writes issued
146 This is the total number of writes issued to this partition.
147
148 Field 4 -- # of sectors written
149 This is the total number of sectors requested to be written to
150 this partition.
151
152 Note that since the address is translated to a disk-relative one, and no
153 record of the partition-relative address is kept, the subsequent success
154 or failure of the read cannot be attributed to the partition. In other
155 words, the number of reads for partitions is counted slightly before time
156 of queuing for partitions, and at completion for whole disks. This is
157 a subtle distinction that is probably uninteresting for most cases.
158
159 More significant is the error induced by counting the numbers of
160 reads/writes before merges for partitions and after for disks. Since a
161 typical workload usually contains a lot of successive and adjacent requests,
162 the number of reads/writes issued can be several times higher than the
163 number of reads/writes completed.
164
165 In 2.6.25, the full statistic set is again available for partitions and
166 disk and partition statistics are consistent again. Since we still don't
167 keep record of the partition-relative address, an operation is attributed to
168 the partition which contains the first sector of the request after the
169 eventual merges. As requests can be merged across partition, this could lead
170 to some (probably insignificant) inaccuracy.
171
172 Additional notes
173 ----------------
174
175 In 2.6+, sysfs is not mounted by default. If your distribution of
176 Linux hasn't added it already, here's the line you'll want to add to
177 your ``/etc/fstab``::
178
179 none /sys sysfs defaults 0 0
180
181
182 In 2.6+, all disk statistics were removed from ``/proc/stat``. In 2.4, they
183 appear in both ``/proc/partitions`` and ``/proc/stat``, although the ones in
184 ``/proc/stat`` take a very different format from those in ``/proc/partitions``
185 (see proc(5), if your system has it.)
186
188

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

I/O 통계 인터페이스와 카운터 성격

1-41

I/O 통계 필드

커널은 `/proc/diskstats`와 `/sys/block/<device>/stat`을 통해 디스크 통계를 노출합니다. 보통 `sar`, `iostat` 같은 도구가 이 통계를 읽습니다.

다음은 파티션 두 개가 있는 디스크의 예입니다.

/proc/diskstats:
  259       0 nvme0n1 255999 814 12369153 47919 996852 81 36123024 425995 0 301795 580470 0 0 0 0 60602 106555
  259       1 nvme0n1p1 492 813 17572 96 848 81 108288 210 0 76 307 0 0 0 0 0 0
  259       2 nvme0n1p2 255401 1 12343477 47799 996004 0 36014736 425784 0 344336 473584 0 0 0 0 0 0

/sys/block/nvme0n1/stat:
  255999 814 12369153 47919 996858 81 36123056 426009 0 301809 580491 0 0 0 0 60605 106562

/sys/block/nvme0n1/nvme0n1p1/stat:
  492 813 17572 96 848 81 108288 210 0 76 307 0 0 0 0 0 0

두 파일은 같은 17개 통계를 담습니다. `/sys/block/<device>/stat`에는 해당 `<device>`의 필드가 있습니다. `/proc/diskstats`에서는 필드 앞에 장치의 major·minor 번호와 장치 이름이 붙습니다. 위 예에서 `nvme0n1`의 첫 통계값은 두 파일 모두 `255999`입니다.

sysfs `stat` 파일은 수가 적고 미리 알려진 디스크 집합을 감시할 때 효율적입니다. 장치를 많이 추적한다면 각 스냅샷마다 여러 파일을 열고 닫는 비용이 없는 `/proc/diskstats`가 더 나은 경우가 많습니다.

필드 9를 제외한 모든 필드는 누적 단조 증가 카운터입니다. 필드 9는 I/O가 완료될 때 0으로 돌아갑니다. 나머지 필드는 부팅, 장치 재연결·재초기화 또는 하부 카운터 오버플로 시 초기화됩니다. 통계 스냅샷을 비교하는 응용 프로그램은 초기화를 탐지하고 처리해야 합니다.

각 통계 집합은 표시된 장치에만 적용됩니다. 시스템 전체 통계가 필요하면 모든 장치를 찾아 합산해야 합니다.

디스크 통계 필드 1~17

42-110
필드이름·형식설명
1완료된 read 수 (`unsigned long`)성공적으로 완료된 read의 총수입니다.
2병합된 read 수 (`unsigned long`)인접한 read와 write는 효율을 위해 병합될 수 있습니다. 두 개의 4K read가 디스크에 전달되기 전에 하나의 8K read가 되어 한 I/O로 계산·대기열 처리될 수 있습니다. 이 필드는 read 병합 횟수입니다.
3읽은 sector 수 (`unsigned long`)성공적으로 읽은 sector의 총수입니다.
4read에 사용한 밀리초 (`unsigned int`)모든 read가 사용한 총 밀리초입니다. `blk_mq_alloc_request()`부터 `__blk_mq_end_request()`까지 측정합니다.
5완료된 write 수 (`unsigned long`)성공적으로 완료된 write의 총수입니다.
6병합된 write 수 (`unsigned long`)필드 2와 같은 방식으로 계산한 write 병합 횟수입니다.
7쓴 sector 수 (`unsigned long`)성공적으로 쓴 sector의 총수입니다.
8write에 사용한 밀리초 (`unsigned int`)모든 write가 사용한 총 밀리초입니다. `blk_mq_alloc_request()`부터 `__blk_mq_end_request()`까지 측정합니다.
9현재 진행 중인 I/O 수 (`unsigned int`)0으로 돌아가야 하는 유일한 필드입니다. 요청이 해당 `struct request_queue`에 전달될 때 증가하고 완료될 때 감소합니다.
10I/O 수행에 사용한 밀리초 (`unsigned int`)필드 9가 0이 아닌 동안 증가합니다. Linux 5.0부터 적어도 한 요청이 시작되거나 완료된 jiffy를 셉니다. 요청이 2 jiffy보다 오래 실행되면 동시 요청이 있을 때 일부 I/O 시간이 누락될 수 있습니다.
11가중 I/O 밀리초 (`unsigned int`)I/O 시작·완료·병합 또는 통계 읽기 때마다, 진행 중인 I/O 수인 필드 9와 마지막 갱신 이후 경과한 I/O 밀리초의 곱만큼 증가합니다. I/O 완료 시간과 누적되는 backlog를 함께 측정하기 쉽습니다.
12완료된 discard 수 (`unsigned long`)성공적으로 완료된 discard의 총수입니다.
13병합된 discard 수 (`unsigned long`)필드 2와 같은 방식으로 계산한 discard 병합 횟수입니다.
14discard한 sector 수 (`unsigned long`)성공적으로 discard한 sector의 총수입니다.
15discard에 사용한 밀리초 (`unsigned int`)모든 discard가 사용한 총 밀리초입니다. `blk_mq_alloc_request()`부터 `__blk_mq_end_request()`까지 측정합니다.
16완료된 flush 요청 수성공적으로 완료된 flush 요청의 총수입니다. 블록 계층은 flush 요청을 결합하고 한 번에 최대 하나만 실행합니다. 디스크가 실행한 flush 요청을 세며 파티션에서는 추적하지 않습니다.
17flush에 사용한 밀리초모든 flush 요청이 사용한 총 밀리초입니다.

카운터 동시성과 시간 정밀도

111-125

성능 병목을 피하기 위해 카운터를 수정할 때 잠금을 잡지 않습니다. 변경이 충돌하면 작은 부정확성이 생길 수 있습니다. 예를 들어 파티션별 발행 read I/O를 모두 합친 값은 디스크의 read I/O와 같아야 하지만, 잠금이 없으므로 매우 가까운 값에 그칠 수 있습니다.

Linux 2.6 이상에는 CPU별(per-CPU) 카운터가 있어 잠금 부재가 거의 문제가 되지 않습니다. 통계를 읽을 때 per-CPU 카운터를 합산하여 사용자에게 제공합니다. 합산 대상 `unsigned long` 변수가 오버플로할 수 있습니다. per-CPU 카운터 자체에 접근하는 편리한 사용자 인터페이스는 없습니다.

Linux 4.19부터 요청 시간은 나노초(nanoseconds) 정밀도로 측정하고, 이 인터페이스에 표시하기 전에 밀리초로 절삭합니다.

디스크와 파티션 통계

126-170

Linux 2.4와 2.6 이상 사이에 I/O 하위 시스템이 크게 바뀌어 일부 통계 정보가 사라졌습니다. 파티션 기준 디스크 주소를 호스트 디스크 기준 주소로 바꾸는 시점이 훨씬 빨라졌고, 병합과 시간 측정은 2.4처럼 디스크와 파티션 양쪽이 아니라 디스크 수준에서만 수행되었습니다.

따라서 2.6 이상에서는 파티션과 디스크의 통계 출력이 달랐고, 파티션에는 다음 네 필드만 제공되었습니다. 위 예시에도 이 차이가 반영되어 있습니다.

필드이름설명
1발행된 read 수이 파티션에 발행된 read의 총수입니다.
2읽은 sector 수이 파티션에서 읽도록 요청된 sector의 총수입니다.
3발행된 write 수이 파티션에 발행된 write의 총수입니다.
4쓴 sector 수이 파티션에 쓰도록 요청된 sector의 총수입니다.

주소를 디스크 기준으로 변환한 뒤 파티션 기준 주소 기록을 유지하지 않으므로 후속 read 성공이나 실패를 파티션에 귀속할 수 없습니다. 파티션 read 수는 파티션 대기열에 들어가기 직전에 세고, 전체 디스크 read 수는 완료 시 셉니다. 대부분의 경우 중요하지 않은 미세한 차이입니다.

더 중요한 오차는 파티션에서는 병합 전에 read·write 수를 세고 디스크에서는 병합 후에 센다는 점입니다. 일반적인 워크로드에는 연속되고 인접한 요청이 많으므로 발행된 read·write 수가 완료된 수보다 몇 배 클 수 있습니다.

Linux 2.6.25에서는 파티션에도 전체 통계 집합을 다시 제공하여 디스크와 파티션 통계가 다시 일관되게 되었습니다. 여전히 파티션 기준 주소를 기록하지 않으므로 최종 병합 후 요청의 첫 sector가 속한 파티션에 연산을 귀속합니다. 요청이 파티션 경계를 넘어 병합될 수 있어 대개 중요하지 않은 작은 부정확성이 생길 수 있습니다.

추가 참고 사항

171-187

Linux 2.6 이상에서는 sysfs가 기본으로 마운트되지 않았습니다. 배포판이 아직 추가하지 않았다면 `/etc/fstab`에 다음 줄을 추가합니다.

none /sys sysfs defaults 0 0

Linux 2.6 이상에서는 `/proc/stat`에서 모든 디스크 통계를 제거했습니다. Linux 2.4에서는 `/proc/partitions`와 `/proc/stat` 양쪽에 나타나지만 `/proc/stat`의 형식은 `/proc/partitions`와 매우 다릅니다. 시스템에 있다면 `proc(5)`를 참조하십시오.

원문 작성자는 `[email protected]`입니다.