|
15 | 15 | #include <stdlib.h> |
16 | 16 | #include <string.h> |
17 | 17 | #include <unistd.h> |
| 18 | +#include <time.h> |
18 | 19 |
|
19 | 20 | #include <sys/stat.h> |
20 | 21 | #include <sys/types.h> |
@@ -884,6 +885,276 @@ __public char *libnvme_path_get_numa_nodes(libnvme_path_t p) |
884 | 885 | return p->numa_nodes; |
885 | 886 | } |
886 | 887 |
|
| 888 | +static libnvme_stat_t libnvme_path_get_stat(libnvme_path_t p, unsigned int idx) |
| 889 | +{ |
| 890 | + if (idx > 1) |
| 891 | + return NULL; |
| 892 | + |
| 893 | + return &p->stat[idx]; |
| 894 | +} |
| 895 | + |
| 896 | +__public void libnvme_path_reset_stat(libnvme_path_t p) |
| 897 | +{ |
| 898 | + libnvme_stat_t stat = &p->stat[0]; |
| 899 | + |
| 900 | + memset(stat, 0, 2 * sizeof(struct libnvme_stat)); |
| 901 | +} |
| 902 | + |
| 903 | +static int libnvme_update_stat(const char *sysfs_stat_path, libnvme_stat_t stat) |
| 904 | +{ |
| 905 | + int n; |
| 906 | + struct timespec ts; |
| 907 | + unsigned long rd_ios, rd_merges, wr_ios, wr_merges; |
| 908 | + unsigned long dc_ios, dc_merges, fl_ios; |
| 909 | + unsigned long long rd_sectors, wr_sectors, dc_sectors; |
| 910 | + unsigned int rd_ticks, wr_ticks, dc_ticks, fl_ticks; |
| 911 | + unsigned int io_ticks, tot_ticks, inflights; |
| 912 | + |
| 913 | + memset(stat, 0, sizeof(struct libnvme_stat)); |
| 914 | + |
| 915 | + n = sscanf(sysfs_stat_path, |
| 916 | + "%lu %lu %llu %u %lu %lu %llu %u %u %u %u %lu %lu %llu %u %lu %u", |
| 917 | + &rd_ios, &rd_merges, &rd_sectors, &rd_ticks, |
| 918 | + &wr_ios, &wr_merges, &wr_sectors, &wr_ticks, |
| 919 | + &inflights, &io_ticks, &tot_ticks, |
| 920 | + &dc_ios, &dc_merges, &dc_sectors, &dc_ticks, |
| 921 | + &fl_ios, &fl_ticks); |
| 922 | + |
| 923 | + if (n < 17) |
| 924 | + return -EINVAL; |
| 925 | + |
| 926 | + /* update read stat */ |
| 927 | + stat->group[READ].ios = rd_ios; |
| 928 | + stat->group[READ].merges = rd_merges; |
| 929 | + stat->group[READ].sectors = rd_sectors; |
| 930 | + stat->group[READ].ticks = rd_ticks; |
| 931 | + |
| 932 | + /* update write stat */ |
| 933 | + stat->group[WRITE].ios = wr_ios; |
| 934 | + stat->group[WRITE].merges = wr_merges; |
| 935 | + stat->group[WRITE].sectors = wr_sectors; |
| 936 | + stat->group[WRITE].ticks = wr_ticks; |
| 937 | + |
| 938 | + /* update inflight counters and ticks */ |
| 939 | + stat->inflights = inflights; |
| 940 | + stat->io_ticks = io_ticks; |
| 941 | + stat->tot_ticks = tot_ticks; |
| 942 | + |
| 943 | + /* update discard stat */ |
| 944 | + stat->group[DISCARD].ios = dc_ios; |
| 945 | + stat->group[DISCARD].merges = dc_merges; |
| 946 | + stat->group[DISCARD].sectors = dc_sectors; |
| 947 | + stat->group[DISCARD].ticks = dc_ticks; |
| 948 | + |
| 949 | + /* update flush stat */ |
| 950 | + stat->group[FLUSH].ios = fl_ios; |
| 951 | + stat->group[FLUSH].ticks = fl_ticks; |
| 952 | + |
| 953 | + clock_gettime(CLOCK_MONOTONIC, &ts); |
| 954 | + stat->ts_ms = ts.tv_sec * 1000 + (double)ts.tv_nsec / 1e6; |
| 955 | + |
| 956 | + return 0; |
| 957 | +} |
| 958 | + |
| 959 | +__public int libnvme_path_update_stat(libnvme_path_t p, bool diffstat) |
| 960 | +{ |
| 961 | + __cleanup_free char *sysfs_stat_path = NULL; |
| 962 | + libnvme_stat_t stat; |
| 963 | + |
| 964 | + p->diffstat = diffstat; |
| 965 | + p->curr_idx ^= 1; |
| 966 | + stat = libnvme_path_get_stat(p, p->curr_idx); |
| 967 | + if (!stat) |
| 968 | + return -EINVAL; |
| 969 | + |
| 970 | + sysfs_stat_path = libnvme_get_path_attr(p, "stat"); |
| 971 | + if (!sysfs_stat_path) |
| 972 | + return -EINVAL; |
| 973 | + |
| 974 | + return libnvme_update_stat(sysfs_stat_path, stat); |
| 975 | +} |
| 976 | + |
| 977 | +static int libnvme_stat_get_inflights(libnvme_stat_t stat) |
| 978 | +{ |
| 979 | + return stat->inflights; |
| 980 | +} |
| 981 | + |
| 982 | +__public unsigned int libnvme_path_get_inflights(libnvme_path_t p) |
| 983 | +{ |
| 984 | + libnvme_stat_t curr; |
| 985 | + |
| 986 | + curr = libnvme_path_get_stat(p, p->curr_idx); |
| 987 | + if (!curr) |
| 988 | + return 0; |
| 989 | + |
| 990 | + return libnvme_stat_get_inflights(curr); |
| 991 | +} |
| 992 | + |
| 993 | +static int libnvme_stat_get_io_ticks(libnvme_stat_t curr, libnvme_stat_t prev, |
| 994 | + bool diffstat) |
| 995 | +{ |
| 996 | + unsigned int delta = 0; |
| 997 | + |
| 998 | + if (!diffstat) |
| 999 | + return curr->io_ticks; |
| 1000 | + |
| 1001 | + if (curr->io_ticks > prev->io_ticks) |
| 1002 | + delta = curr->io_ticks - prev->io_ticks; |
| 1003 | + |
| 1004 | + return delta; |
| 1005 | +} |
| 1006 | + |
| 1007 | +__public unsigned int libnvme_path_get_io_ticks(libnvme_path_t p) |
| 1008 | +{ |
| 1009 | + libnvme_stat_t curr, prev; |
| 1010 | + |
| 1011 | + curr = libnvme_path_get_stat(p, p->curr_idx); |
| 1012 | + prev = libnvme_path_get_stat(p, !p->curr_idx); |
| 1013 | + |
| 1014 | + if (!curr || !prev) |
| 1015 | + return 0; |
| 1016 | + |
| 1017 | + return libnvme_stat_get_io_ticks(curr, prev, p->diffstat); |
| 1018 | +} |
| 1019 | + |
| 1020 | +static unsigned int libnvme_stat_get_ticks(libnvme_stat_t curr, |
| 1021 | + libnvme_stat_t prev, enum libnvme_stat_group grp, bool diffstat) |
| 1022 | +{ |
| 1023 | + unsigned int delta = 0; |
| 1024 | + |
| 1025 | + if (!diffstat) |
| 1026 | + return curr->group[grp].ticks; |
| 1027 | + |
| 1028 | + if (curr->group[grp].ticks > prev->group[grp].ticks) |
| 1029 | + delta = curr->group[grp].ticks - prev->group[grp].ticks; |
| 1030 | + |
| 1031 | + return delta; |
| 1032 | +} |
| 1033 | + |
| 1034 | +static unsigned int __libnvme_path_get_ticks(libnvme_path_t p, |
| 1035 | + enum libnvme_stat_group grp) |
| 1036 | +{ |
| 1037 | + libnvme_stat_t curr, prev; |
| 1038 | + |
| 1039 | + curr = libnvme_path_get_stat(p, p->curr_idx); |
| 1040 | + prev = libnvme_path_get_stat(p, !p->curr_idx); |
| 1041 | + |
| 1042 | + if (!curr || !prev) |
| 1043 | + return 0; |
| 1044 | + |
| 1045 | + return libnvme_stat_get_ticks(curr, prev, grp, p->diffstat); |
| 1046 | +} |
| 1047 | + |
| 1048 | +__public unsigned int libnvme_path_get_read_ticks(libnvme_path_t p) |
| 1049 | +{ |
| 1050 | + return __libnvme_path_get_ticks(p, READ); |
| 1051 | +} |
| 1052 | + |
| 1053 | +__public unsigned int libnvme_path_get_write_ticks(libnvme_path_t p) |
| 1054 | +{ |
| 1055 | + return __libnvme_path_get_ticks(p, WRITE); |
| 1056 | +} |
| 1057 | + |
| 1058 | +static double libnvme_stat_get_interval(libnvme_stat_t curr, |
| 1059 | + libnvme_stat_t prev) |
| 1060 | +{ |
| 1061 | + double delta = 0.0; |
| 1062 | + |
| 1063 | + if (prev->ts_ms && curr->ts_ms > prev->ts_ms) |
| 1064 | + delta = curr->ts_ms - prev->ts_ms; |
| 1065 | + |
| 1066 | + return delta; |
| 1067 | +} |
| 1068 | + |
| 1069 | +__public double libnvme_path_get_stat_interval(libnvme_path_t p) |
| 1070 | +{ |
| 1071 | + libnvme_stat_t curr, prev; |
| 1072 | + |
| 1073 | + curr = libnvme_path_get_stat(p, p->curr_idx); |
| 1074 | + prev = libnvme_path_get_stat(p, !p->curr_idx); |
| 1075 | + |
| 1076 | + if (!curr || !prev) |
| 1077 | + return 0; |
| 1078 | + |
| 1079 | + return libnvme_stat_get_interval(curr, prev); |
| 1080 | +} |
| 1081 | + |
| 1082 | +static unsigned long libnvme_stat_get_ios(libnvme_stat_t curr, |
| 1083 | + libnvme_stat_t prev, enum libnvme_stat_group grp, bool diffstat) |
| 1084 | +{ |
| 1085 | + unsigned long ios = 0; |
| 1086 | + |
| 1087 | + if (!diffstat) |
| 1088 | + return curr->group[grp].ios; |
| 1089 | + |
| 1090 | + if (curr->group[grp].ios > prev->group[grp].ios) |
| 1091 | + ios = curr->group[grp].ios - prev->group[grp].ios; |
| 1092 | + |
| 1093 | + return ios; |
| 1094 | +} |
| 1095 | + |
| 1096 | +static unsigned long __libnvme_path_get_ios(libnvme_path_t p, |
| 1097 | + enum libnvme_stat_group grp) |
| 1098 | +{ |
| 1099 | + libnvme_stat_t curr, prev; |
| 1100 | + |
| 1101 | + curr = libnvme_path_get_stat(p, p->curr_idx); |
| 1102 | + prev = libnvme_path_get_stat(p, !p->curr_idx); |
| 1103 | + |
| 1104 | + if (!curr || !prev) |
| 1105 | + return 0; |
| 1106 | + |
| 1107 | + return libnvme_stat_get_ios(curr, prev, grp, p->diffstat); |
| 1108 | +} |
| 1109 | + |
| 1110 | +__public unsigned long libnvme_path_get_read_ios(libnvme_path_t p) |
| 1111 | +{ |
| 1112 | + return __libnvme_path_get_ios(p, READ); |
| 1113 | +} |
| 1114 | + |
| 1115 | +__public unsigned long libnvme_path_get_write_ios(libnvme_path_t p) |
| 1116 | +{ |
| 1117 | + return __libnvme_path_get_ios(p, WRITE); |
| 1118 | +} |
| 1119 | + |
| 1120 | +static unsigned long long libnvme_stat_get_sectors(libnvme_stat_t curr, |
| 1121 | + libnvme_stat_t prev, enum libnvme_stat_group grp, bool diffstat) |
| 1122 | +{ |
| 1123 | + unsigned long long sec = 0; |
| 1124 | + |
| 1125 | + if (!diffstat) |
| 1126 | + return curr->group[grp].sectors; |
| 1127 | + |
| 1128 | + if (curr->group[grp].sectors > prev->group[grp].sectors) |
| 1129 | + sec = curr->group[grp].sectors - prev->group[grp].sectors; |
| 1130 | + |
| 1131 | + return sec; |
| 1132 | +} |
| 1133 | + |
| 1134 | +static unsigned long long __libnvme_path_get_sectors(libnvme_path_t p, |
| 1135 | + enum libnvme_stat_group grp) |
| 1136 | +{ |
| 1137 | + libnvme_stat_t curr, prev; |
| 1138 | + |
| 1139 | + curr = libnvme_path_get_stat(p, p->curr_idx); |
| 1140 | + prev = libnvme_path_get_stat(p, !p->curr_idx); |
| 1141 | + |
| 1142 | + if (!curr || !prev) |
| 1143 | + return 0; |
| 1144 | + |
| 1145 | + return libnvme_stat_get_sectors(curr, prev, grp, p->diffstat); |
| 1146 | +} |
| 1147 | + |
| 1148 | +__public unsigned long long libnvme_path_get_read_sectors(libnvme_path_t p) |
| 1149 | +{ |
| 1150 | + return __libnvme_path_get_sectors(p, READ); |
| 1151 | +} |
| 1152 | + |
| 1153 | +__public unsigned long long libnvme_path_get_write_sectors(libnvme_path_t p) |
| 1154 | +{ |
| 1155 | + return __libnvme_path_get_sectors(p, WRITE); |
| 1156 | +} |
| 1157 | + |
887 | 1158 | void nvme_free_path(struct libnvme_path *p) |
888 | 1159 | { |
889 | 1160 | if (!p) |
|
0 commit comments