xref: /openbmc/qemu/util/qemu-progress.c (revision 16a18f26)
1baacf047SPaolo Bonzini /*
2baacf047SPaolo Bonzini  * QEMU progress printing utility functions
3baacf047SPaolo Bonzini  *
4baacf047SPaolo Bonzini  * Copyright (C) 2011 Jes Sorensen <Jes.Sorensen@redhat.com>
5baacf047SPaolo Bonzini  *
6baacf047SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
7baacf047SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
8baacf047SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
9baacf047SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10baacf047SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
11baacf047SPaolo Bonzini  * furnished to do so, subject to the following conditions:
12baacf047SPaolo Bonzini  *
13baacf047SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
14baacf047SPaolo Bonzini  * all copies or substantial portions of the Software.
15baacf047SPaolo Bonzini  *
16baacf047SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17baacf047SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18baacf047SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19baacf047SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20baacf047SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21baacf047SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22baacf047SPaolo Bonzini  * THE SOFTWARE.
23baacf047SPaolo Bonzini  */
24baacf047SPaolo Bonzini 
25baacf047SPaolo Bonzini #include "qemu/osdep.h"
26*16a18f26SMarc-André Lureau #include "qemu/qemu-progress.h"
27baacf047SPaolo Bonzini 
28baacf047SPaolo Bonzini struct progress_state {
29baacf047SPaolo Bonzini     float current;
30baacf047SPaolo Bonzini     float last_print;
31baacf047SPaolo Bonzini     float min_skip;
32baacf047SPaolo Bonzini     void (*print)(void);
33baacf047SPaolo Bonzini     void (*end)(void);
34baacf047SPaolo Bonzini };
35baacf047SPaolo Bonzini 
36baacf047SPaolo Bonzini static struct progress_state state;
37baacf047SPaolo Bonzini static volatile sig_atomic_t print_pending;
38baacf047SPaolo Bonzini 
39baacf047SPaolo Bonzini /*
40baacf047SPaolo Bonzini  * Simple progress print function.
41baacf047SPaolo Bonzini  * @percent relative percent of current operation
42baacf047SPaolo Bonzini  * @max percent of total operation
43baacf047SPaolo Bonzini  */
progress_simple_print(void)44baacf047SPaolo Bonzini static void progress_simple_print(void)
45baacf047SPaolo Bonzini {
46baacf047SPaolo Bonzini     printf("    (%3.2f/100%%)\r", state.current);
47baacf047SPaolo Bonzini     fflush(stdout);
48baacf047SPaolo Bonzini }
49baacf047SPaolo Bonzini 
progress_simple_end(void)50baacf047SPaolo Bonzini static void progress_simple_end(void)
51baacf047SPaolo Bonzini {
52baacf047SPaolo Bonzini     printf("\n");
53baacf047SPaolo Bonzini }
54baacf047SPaolo Bonzini 
progress_simple_init(void)55baacf047SPaolo Bonzini static void progress_simple_init(void)
56baacf047SPaolo Bonzini {
57baacf047SPaolo Bonzini     state.print = progress_simple_print;
58baacf047SPaolo Bonzini     state.end = progress_simple_end;
59baacf047SPaolo Bonzini }
60baacf047SPaolo Bonzini 
61baacf047SPaolo Bonzini #ifdef CONFIG_POSIX
sigusr_print(int signal)62baacf047SPaolo Bonzini static void sigusr_print(int signal)
63baacf047SPaolo Bonzini {
64baacf047SPaolo Bonzini     print_pending = 1;
65baacf047SPaolo Bonzini }
66baacf047SPaolo Bonzini #endif
67baacf047SPaolo Bonzini 
progress_dummy_print(void)68baacf047SPaolo Bonzini static void progress_dummy_print(void)
69baacf047SPaolo Bonzini {
70baacf047SPaolo Bonzini     if (print_pending) {
71baacf047SPaolo Bonzini         fprintf(stderr, "    (%3.2f/100%%)\n", state.current);
72baacf047SPaolo Bonzini         print_pending = 0;
73baacf047SPaolo Bonzini     }
74baacf047SPaolo Bonzini }
75baacf047SPaolo Bonzini 
progress_dummy_end(void)76baacf047SPaolo Bonzini static void progress_dummy_end(void)
77baacf047SPaolo Bonzini {
78baacf047SPaolo Bonzini }
79baacf047SPaolo Bonzini 
progress_dummy_init(void)80baacf047SPaolo Bonzini static void progress_dummy_init(void)
81baacf047SPaolo Bonzini {
82baacf047SPaolo Bonzini #ifdef CONFIG_POSIX
83baacf047SPaolo Bonzini     struct sigaction action;
843c4b4e38SKevin Wolf     sigset_t set;
85baacf047SPaolo Bonzini 
86baacf047SPaolo Bonzini     memset(&action, 0, sizeof(action));
87baacf047SPaolo Bonzini     sigfillset(&action.sa_mask);
88baacf047SPaolo Bonzini     action.sa_handler = sigusr_print;
89baacf047SPaolo Bonzini     action.sa_flags = 0;
90baacf047SPaolo Bonzini     sigaction(SIGUSR1, &action, NULL);
91262fbae6SMax Reitz #ifdef SIGINFO
92262fbae6SMax Reitz     sigaction(SIGINFO, &action, NULL);
93262fbae6SMax Reitz #endif
943c4b4e38SKevin Wolf 
953c4b4e38SKevin Wolf     /*
963c4b4e38SKevin Wolf      * SIGUSR1 is SIG_IPI and gets blocked in qemu_init_main_loop(). In the
973c4b4e38SKevin Wolf      * tools that use the progress report SIGUSR1 isn't used in this meaning
983c4b4e38SKevin Wolf      * and instead should print the progress, so reenable it.
993c4b4e38SKevin Wolf      */
1003c4b4e38SKevin Wolf     sigemptyset(&set);
1013c4b4e38SKevin Wolf     sigaddset(&set, SIGUSR1);
1023c4b4e38SKevin Wolf     pthread_sigmask(SIG_UNBLOCK, &set, NULL);
103baacf047SPaolo Bonzini #endif
104baacf047SPaolo Bonzini 
105baacf047SPaolo Bonzini     state.print = progress_dummy_print;
106baacf047SPaolo Bonzini     state.end = progress_dummy_end;
107baacf047SPaolo Bonzini }
108baacf047SPaolo Bonzini 
109baacf047SPaolo Bonzini /*
110baacf047SPaolo Bonzini  * Initialize progress reporting.
111baacf047SPaolo Bonzini  * If @enabled is false, actual reporting is suppressed.  The user can
112baacf047SPaolo Bonzini  * still trigger a report by sending a SIGUSR1.
113baacf047SPaolo Bonzini  * Reports are also suppressed unless we've had at least @min_skip
114baacf047SPaolo Bonzini  * percent progress since the last report.
115baacf047SPaolo Bonzini  */
qemu_progress_init(int enabled,float min_skip)116baacf047SPaolo Bonzini void qemu_progress_init(int enabled, float min_skip)
117baacf047SPaolo Bonzini {
118baacf047SPaolo Bonzini     state.min_skip = min_skip;
119baacf047SPaolo Bonzini     if (enabled) {
120baacf047SPaolo Bonzini         progress_simple_init();
121baacf047SPaolo Bonzini     } else {
122baacf047SPaolo Bonzini         progress_dummy_init();
123baacf047SPaolo Bonzini     }
124baacf047SPaolo Bonzini }
125baacf047SPaolo Bonzini 
qemu_progress_end(void)126baacf047SPaolo Bonzini void qemu_progress_end(void)
127baacf047SPaolo Bonzini {
128baacf047SPaolo Bonzini     state.end();
129baacf047SPaolo Bonzini }
130baacf047SPaolo Bonzini 
131baacf047SPaolo Bonzini /*
132baacf047SPaolo Bonzini  * Report progress.
133baacf047SPaolo Bonzini  * @delta is how much progress we made.
1348cc360b9Szhaolichang  * If @max is zero, @delta is an absolute value of the total job done.
135baacf047SPaolo Bonzini  * Else, @delta is a progress delta since the last call, as a fraction
136baacf047SPaolo Bonzini  * of @max.  I.e. the delta is @delta * @max / 100. This allows
137baacf047SPaolo Bonzini  * relative accounting of functions which may be a different fraction of
138baacf047SPaolo Bonzini  * the full job, depending on the context they are called in. I.e.
139baacf047SPaolo Bonzini  * a function might be considered 40% of the full job if used from
140baacf047SPaolo Bonzini  * bdrv_img_create() but only 20% if called from img_convert().
141baacf047SPaolo Bonzini  */
qemu_progress_print(float delta,int max)142baacf047SPaolo Bonzini void qemu_progress_print(float delta, int max)
143baacf047SPaolo Bonzini {
144baacf047SPaolo Bonzini     float current;
145baacf047SPaolo Bonzini 
146baacf047SPaolo Bonzini     if (max == 0) {
147baacf047SPaolo Bonzini         current = delta;
148baacf047SPaolo Bonzini     } else {
149baacf047SPaolo Bonzini         current = state.current + delta / 100 * max;
150baacf047SPaolo Bonzini     }
151baacf047SPaolo Bonzini     if (current > 100) {
152baacf047SPaolo Bonzini         current = 100;
153baacf047SPaolo Bonzini     }
154baacf047SPaolo Bonzini     state.current = current;
155baacf047SPaolo Bonzini 
156baacf047SPaolo Bonzini     if (current > (state.last_print + state.min_skip) ||
157bd5072d7SMax Reitz         current < (state.last_print - state.min_skip) ||
158bd5072d7SMax Reitz         current == 100 || current == 0) {
159baacf047SPaolo Bonzini         state.last_print = state.current;
160baacf047SPaolo Bonzini         state.print();
161baacf047SPaolo Bonzini     }
162baacf047SPaolo Bonzini }
163