dsynth - Add skip count for ignored and other failure conditions
[dragonfly.git] / usr.bin / dsynth / runstats.c
1 /*
2  * Copyright (c) 2019 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * This code uses concepts and configuration based on 'synth', by
8  * John R. Marino <draco@marino.st>, which was written in ada.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  * 3. Neither the name of The DragonFly Project nor the names of its
21  *    contributors may be used to endorse or promote products derived
22  *    from this software without specific, prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
28  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37
38 #include "dsynth.h"
39
40 static runstats_t *RSBase;
41 static runstats_t **RSTailp = &RSBase;
42 static time_t RSStartTime;
43
44 #define RHISTSIZE       600             /* impulse record is 10 minutes */
45 #define ONEHOUR         (60 * 60)
46
47 void
48 RunStatsInit(void)
49 {
50         runstats_t *rs;
51
52         RSStartTime = time(NULL);
53
54         *RSTailp = &NCursesRunStats;
55         RSTailp = &(*RSTailp)->next;
56
57         *RSTailp = &MonitorRunStats;
58         RSTailp = &(*RSTailp)->next;
59
60         *RSTailp = &HtmlRunStats;
61         RSTailp = &(*RSTailp)->next;
62
63         for (rs = RSBase; rs; rs = rs->next)
64                 rs->init();
65 }
66
67 void
68 RunStatsDone(void)
69 {
70         runstats_t *rs;
71
72         for (rs = RSBase; rs; rs = rs->next)
73                 rs->done();
74 }
75
76 void
77 RunStatsReset(void)
78 {
79         runstats_t *rs;
80
81         for (rs = RSBase; rs; rs = rs->next)
82                 rs->reset();
83 }
84
85 void
86 RunStatsUpdate(worker_t *work, const char *portdir)
87 {
88         runstats_t *rs;
89
90         for (rs = RSBase; rs; rs = rs->next)
91                 rs->update(work, portdir);
92 }
93
94 void
95 RunStatsUpdateTop(int active)
96 {
97         static int rate_history[RHISTSIZE];
98         static u_int last_ti;
99         topinfo_t info;
100         runstats_t *rs;
101         u_int ti;
102         time_t t;
103
104         /*
105          * Time
106          */
107         bzero(&info, sizeof(info));
108         t = time(NULL) - RSStartTime;
109         info.s = t % 60;
110         info.m = t / 60 % 60;
111         info.h = t / 60 / 60;
112         info.active = active;
113
114         /*
115          * Easy fields
116          */
117         info.total = BuildTotal;
118         info.successful = BuildSuccessCount;
119         info.ignored = BuildIgnoreCount;
120         info.remaining = BuildTotal - BuildCount;
121         info.failed = BuildFailCount;
122         info.skipped = BuildSkipCount;
123
124         /*
125          * Load and swap
126          */
127         getloadavg(info.dload, 3);
128         info.dswap = getswappct(&info.noswap) * 100.0;
129
130         /*
131          * Rate and 10-minute impulse
132          */
133         if (t > 20)
134                 info.pkgrate = (BuildSuccessCount + BuildFailCount) *
135                                ONEHOUR / t;
136         else
137                 info.pkgrate = 0;
138         ti = (u_int)((unsigned long)t % RHISTSIZE);
139         rate_history[ti] = BuildSuccessCount + BuildFailCount;
140 #if 0
141         dlog(DLOG_ALL, "ti[%3d] = %d\n", ti, rate_history[ti]);
142 #endif
143         while (last_ti != ti) {
144                 rate_history[last_ti] = rate_history[ti];
145                 last_ti = (last_ti + 1) % RHISTSIZE;
146         }
147
148         if (t < 20) {
149                 info.pkgimpulse = 0;
150         } else if (t < RHISTSIZE) {
151                 info.pkgimpulse = rate_history[ti] -
152                                   rate_history[(ti - t) % RHISTSIZE];
153                 info.pkgimpulse = info.pkgimpulse * ONEHOUR / t;
154         } else {
155                 info.pkgimpulse = rate_history[ti] -
156                                   rate_history[(ti + 1) % RHISTSIZE];
157                 info.pkgimpulse = info.pkgimpulse * ONEHOUR / RHISTSIZE;
158 #if 0
159                 dlog(DLOG_ALL, "pkgimpulse %d - %d -> %d\n",
160                      rate_history[ti],
161                      rate_history[(ti + 1) % RHISTSIZE],
162                      info.pkgimpulse);
163 #endif
164         }
165
166         info.dynmaxworkers = DynamicMaxWorkers;
167
168         /*
169          * Issue update
170          */
171         for (rs = RSBase; rs; rs = rs->next)
172                 rs->updateTop(&info);
173 }
174
175 void
176 RunStatsUpdateLogs(void)
177 {
178         runstats_t *rs;
179
180         for (rs = RSBase; rs; rs = rs->next)
181                 rs->updateLogs();
182 }
183
184 void
185 RunStatsSync(void)
186 {
187         runstats_t *rs;
188
189         for (rs = RSBase; rs; rs = rs->next)
190                 rs->sync();
191 }
192
193 void
194 RunStatsUpdateCompletion(worker_t *work, int logid, pkg_t *pkg,
195                          const char *reason, const char *skipbuf)
196 {
197         runstats_t *rs;
198
199         for (rs = RSBase; rs; rs = rs->next) {
200                 if (rs->updateCompletion)
201                         rs->updateCompletion(work, logid, pkg, reason, skipbuf);
202         }
203 }