i3 - improved tiling WM


add thread usage indicator

Patch status: rejected

Patch by Vadim Zubov

Long description:

show load for every thread independently

in i3config file need to add such strings:
threads_usage {
  format = "%usage"
}

To apply this patch, use:
curl http://cr.i3wm.org/patch/229/raw.patch | git am

b/i3status.c

22
@@ -309,6 +309,7 @@ int main(int argc, char *argv[]) {
23
                 CFG_SEC("ddate", ddate_opts, CFGF_NONE),
24
                 CFG_SEC("load", load_opts, CFGF_NONE),
25
                 CFG_SEC("cpu_usage", usage_opts, CFGF_NONE),
26
+                CFG_SEC("threads_usage", usage_opts, CFGF_NONE),
27
                 CFG_CUSTOM_COLOR_OPTS,
28
                 CFG_END()
29
         };
30
@@ -530,6 +531,11 @@ int main(int argc, char *argv[]) {
31
                                 print_cpu_usage(json_gen, buffer, cfg_getstr(sec, "format"));
32
                                 SEC_CLOSE_MAP;
33
                         }
34
+                        CASE_SEC("threads_usage") {
35
+                                SEC_OPEN_MAP("threads_usage");
36
+                                print_threads_usage(json_gen, buffer, cfg_getstr(sec, "format"));
37
+                                SEC_CLOSE_MAP;
38
+                        }
39
                 }
40
                 if (output_format == O_I3BAR) {
41
                         yajl_gen_array_close(json_gen);

b/include/i3status.h

46
@@ -151,6 +151,7 @@ void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface,
47
 void print_run_watch(yajl_gen json_gen, char *buffer, const char *title, const char *pidfile, const char *format);
48
 void print_cpu_temperature_info(yajl_gen json_gen, char *buffer, int zone, const char *path, const char *format, int);
49
 void print_cpu_usage(yajl_gen json_gen, char *buffer, const char *format);
50
+void print_threads_usage(yajl_gen json_gen, char *buffer, const char *format);
51
 void print_eth_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down);
52
 void print_load(yajl_gen json_gen, char *buffer, const char *format, const float max_threshold);
53
 void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char *device, const char *mixer, int mixer_idx);

b/src/print_threads_usage.c

59
@@ -0,0 +1,150 @@
60
+// vim:sw=8:sts=8:ts=8:expandtab
61
+#include <stdlib.h>
62
+#include <limits.h>
63
+#include <stdio.h>
64
+#include <string.h>
65
+#include <yajl/yajl_gen.h>
66
+#include <yajl/yajl_version.h>
67
+
68
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
69
+#include <sys/param.h>
70
+#include <sys/types.h>
71
+#include <sys/sysctl.h>
72
+#include <sys/dkstat.h>
73
+#endif
74
+
75
+#if defined(__DragonFly__)
76
+#include <sys/param.h>
77
+#include <sys/types.h>
78
+#include <sys/sysctl.h>
79
+#include <sys/resource.h>
80
+#endif
81
+
82
+#include "i3status.h"
83
+
84
+#if defined(LINUX)
85
+static int *prev_total = 0;
86
+static int *prev_idle  = 0;
87
+#else
88
+static int prev_total = 0;
89
+static int prev_idle  = 0;
90
+#endif
91
+
92
+/*
93
+ * Reads the threads utilization from /proc/stat and returns the usage as a
94
+ * percentage.
95
+ *
96
+ */
97
+void print_threads_usage(yajl_gen json_gen, char *buffer, const char *format) {
98
+        const char *walk;
99
+        char *outwalk = buffer;
100
+        char buf[1024];
101
+        char scanf_string[1024];
102
+        int curr_user = 0, curr_nice = 0, curr_system = 0, curr_idle = 0, curr_total;
103
+        int diff_idle, diff_total, diff_usage;
104
+
105
+#if defined(LINUX)
106
+        static char statpath[512];
107
+        strcpy(statpath, "/proc/stat");
108
+        if (!slurp(statpath, buf, sizeof(buf)))
109
+            goto error;
110
+
111
+        char *cpu_pos = buf;
112
+        int cpu_total = 0, cpu_counter = 0;
113
+        do {
114
+            cpu_counter++;
115
+            cpu_pos += strlen("cpu");
116
+            cpu_pos  = strstr(cpu_pos, "cpu");
117
+        }
118
+        while (cpu_pos);
119
+        cpu_total = cpu_counter - 1;
120
+        if (cpu_total <= 0)
121
+            goto error;
122
+        // cpu  ... -- skip this string
123
+        // cpu0 ...
124
+        // cpu1 ...
125
+
126
+        int *diff_usage_cpus = malloc (cpu_total * sizeof (int));
127
+        if (prev_total == 0)
128
+        {
129
+            prev_total = malloc (cpu_total * sizeof (int));
130
+            prev_idle  = malloc (cpu_total * sizeof (int));
131
+            memset (prev_total, 0, cpu_total * sizeof (int));
132
+            memset (prev_idle,  0, cpu_total * sizeof (int));
133
+        }
134
+
135
+        cpu_counter = 0;
136
+        cpu_pos = strstr(buf, "cpu");
137
+        for (cpu_counter = 0; cpu_counter < cpu_total; cpu_counter++) {
138
+                cpu_pos += strlen("cpu");
139
+                cpu_pos  = strstr(cpu_pos, "cpu");
140
+                sprintf (scanf_string, "cpu%d %s", cpu_counter, "%d %d %d %d");
141
+                if (sscanf(cpu_pos, scanf_string, &curr_user, &curr_nice, &curr_system, &curr_idle) != 4)
142
+                       goto error;
143
+                curr_total = curr_user + curr_nice + curr_system + curr_idle;
144
+                diff_idle  = curr_idle - prev_idle[cpu_counter];
145
+                diff_total = curr_total - prev_total[cpu_counter];
146
+                diff_usage = (diff_total ? (1000 * (diff_total - diff_idle)/diff_total + 5)/10 : 0);
147
+                prev_total[cpu_counter] = curr_total;
148
+                prev_idle[cpu_counter]  = curr_idle;
149
+                diff_usage_cpus[cpu_counter] = diff_usage;
150
+        }
151
+
152
+#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
153
+
154
+#if defined(__FreeBSD__) || defined(__DragonFly__)
155
+        size_t size;
156
+        long cp_time[CPUSTATES];
157
+        size = sizeof cp_time;
158
+        if (sysctlbyname("kern.cp_time", &cp_time, &size, NULL, 0) < 0)
159
+                goto error;
160
+#else
161
+	/* This information is taken from the boot cpu, any other cpus are currently ignored. */
162
+	long cp_time[CPUSTATES];
163
+	int mib[2];
164
+	size_t size = sizeof(cp_time);
165
+
166
+	mib[0] = CTL_KERN;
167
+	mib[1] = KERN_CPTIME;
168
+
169
+	if (sysctl(mib, 2, cp_time, &size, NULL, 0))
170
+		goto error;
171
+#endif
172
+
173
+        curr_user = cp_time[CP_USER];
174
+        curr_nice = cp_time[CP_NICE];
175
+        curr_system = cp_time[CP_SYS];
176
+        curr_idle = cp_time[CP_IDLE];
177
+        curr_total = curr_user + curr_nice + curr_system + curr_idle;
178
+        diff_idle  = curr_idle - prev_idle;
179
+        diff_total = curr_total - prev_total;
180
+        diff_usage = (diff_total ? (1000 * (diff_total - diff_idle)/diff_total + 5)/10 : 0);
181
+        prev_total = curr_total;
182
+        prev_idle  = curr_idle;
183
+#else
184
+        goto error;
185
+#endif
186
+        for (walk = format; *walk != '\0'; walk++) {
187
+                if (*walk != '%') {
188
+                        *(outwalk++) = *walk;
189
+                        continue;
190
+                }
191
+
192
+                if (strncmp(walk+1, "usage", strlen("usage")) == 0) {
193
+#if defined(LINUX)
194
+                        for (cpu_counter = 0; cpu_counter < cpu_total; cpu_counter++)
195
+                            outwalk += sprintf(outwalk, "%02d%% ", diff_usage_cpus[cpu_counter]);
196
+                        outwalk--;// disable last whitespace
197
+#else
198
+                        outwalk += sprintf(outwalk, "%02d%%", diff_usage);
199
+#endif
200
+                        walk += strlen("usage");
201
+                }
202
+        }
203
+
204
+        OUTPUT_FULL_TEXT(buffer);
205
+        return;
206
+error:
207
+        OUTPUT_FULL_TEXT("cant read threads usage");
208
+        (void)fputs("i3status: Cannot read threads usage\n", stderr);
209
+}