Refactoring
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
#include "../server.h"
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
@@ -44,7 +45,162 @@
|
||||
#include <librsvg/rsvg.h>
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_LIBUNWIND
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include <libunwind.h>
|
||||
#else
|
||||
#ifdef ENABLE_EXECINFO
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "../panel.h"
|
||||
#include "timer.h"
|
||||
|
||||
void write_string(int fd, const char *s)
|
||||
{
|
||||
int len = strlen(s);
|
||||
while (len > 0) {
|
||||
int count = write(fd, s, len);
|
||||
if (count >= 0) {
|
||||
s += count;
|
||||
len -= count;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void log_string(int fd, const char *s)
|
||||
{
|
||||
write_string(2, s);
|
||||
write_string(fd, s);
|
||||
}
|
||||
|
||||
void dump_backtrace(int log_fd)
|
||||
{
|
||||
#ifndef DISABLE_BACKTRACE
|
||||
log_string(log_fd, "\n" YELLOW "Backtrace:" RESET "\n");
|
||||
|
||||
#ifdef ENABLE_LIBUNWIND
|
||||
unw_cursor_t cursor;
|
||||
unw_context_t context;
|
||||
unw_getcontext(&context);
|
||||
unw_init_local(&cursor, &context);
|
||||
|
||||
while (unw_step(&cursor) > 0) {
|
||||
unw_word_t offset;
|
||||
char fname[128];
|
||||
fname[0] = '\0';
|
||||
(void)unw_get_proc_name(&cursor, fname, sizeof(fname), &offset);
|
||||
log_string(log_fd, fname);
|
||||
log_string(log_fd, "\n");
|
||||
}
|
||||
#else
|
||||
#ifdef ENABLE_EXECINFO
|
||||
#define MAX_TRACE_SIZE 128
|
||||
void *array[MAX_TRACE_SIZE];
|
||||
size_t size = backtrace(array, MAX_TRACE_SIZE);
|
||||
char **strings = backtrace_symbols(array, size);
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
log_string(log_fd, strings[i]);
|
||||
log_string(log_fd, "\n");
|
||||
}
|
||||
|
||||
free(strings);
|
||||
#endif // ENABLE_EXECINFO
|
||||
#endif // ENABLE_LIBUNWIND
|
||||
#endif // DISABLE_BACKTRACE
|
||||
}
|
||||
|
||||
// sleep() returns early when signals arrive. This function does not.
|
||||
void safe_sleep(int seconds)
|
||||
{
|
||||
double t0 = get_time();
|
||||
while (1) {
|
||||
double t = get_time();
|
||||
if (t > t0 + seconds)
|
||||
return;
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
const char *signal_name(int sig)
|
||||
{
|
||||
switch (sig) {
|
||||
case SIGHUP:
|
||||
return "SIGHUP: Hangup (POSIX).";
|
||||
case SIGINT:
|
||||
return "SIGINT: Interrupt (ANSI).";
|
||||
case SIGQUIT:
|
||||
return "SIGQUIT: Quit (POSIX).";
|
||||
case SIGILL:
|
||||
return "SIGILL: Illegal instruction (ANSI).";
|
||||
case SIGTRAP:
|
||||
return "SIGTRAP: Trace trap (POSIX).";
|
||||
case SIGABRT:
|
||||
return "SIGABRT/SIGIOT: Abort (ANSI) / IOT trap (4.2 BSD).";
|
||||
case SIGBUS:
|
||||
return "SIGBUS: BUS error (4.2 BSD).";
|
||||
case SIGFPE:
|
||||
return "SIGFPE: Floating-point exception (ANSI).";
|
||||
case SIGKILL:
|
||||
return "SIGKILL: Kill, unblockable (POSIX).";
|
||||
case SIGUSR1:
|
||||
return "SIGUSR1: User-defined signal 1 (POSIX).";
|
||||
case SIGSEGV:
|
||||
return "SIGSEGV: Segmentation violation (ANSI).";
|
||||
case SIGUSR2:
|
||||
return "SIGUSR2: User-defined signal 2 (POSIX).";
|
||||
case SIGPIPE:
|
||||
return "SIGPIPE: Broken pipe (POSIX).";
|
||||
case SIGALRM:
|
||||
return "SIGALRM: Alarm clock (POSIX).";
|
||||
case SIGTERM:
|
||||
return "SIGTERM: Termination (ANSI).";
|
||||
// case SIGSTKFLT: return "SIGSTKFLT: Stack fault.";
|
||||
case SIGCHLD:
|
||||
return "SIGCHLD: Child status has changed (POSIX).";
|
||||
case SIGCONT:
|
||||
return "SIGCONT: Continue (POSIX).";
|
||||
case SIGSTOP:
|
||||
return "SIGSTOP: Stop, unblockable (POSIX).";
|
||||
case SIGTSTP:
|
||||
return "SIGTSTP: Keyboard stop (POSIX).";
|
||||
case SIGTTIN:
|
||||
return "SIGTTIN: Background read from tty (POSIX).";
|
||||
case SIGTTOU:
|
||||
return "SIGTTOU: Background write to tty (POSIX).";
|
||||
case SIGURG:
|
||||
return "SIGURG: Urgent condition on socket (4.2 BSD).";
|
||||
case SIGXCPU:
|
||||
return "SIGXCPU: CPU limit exceeded (4.2 BSD).";
|
||||
case SIGXFSZ:
|
||||
return "SIGXFSZ: File size limit exceeded (4.2 BSD).";
|
||||
case SIGVTALRM:
|
||||
return "SIGVTALRM: Virtual alarm clock (4.2 BSD).";
|
||||
case SIGPROF:
|
||||
return "SIGPROF: Profiling alarm clock (4.2 BSD).";
|
||||
// case SIGPWR: return "SIGPWR: Power failure restart (System V).";
|
||||
case SIGSYS:
|
||||
return "SIGSYS: Bad system call.";
|
||||
}
|
||||
static char s[64];
|
||||
sprintf(s, "SIG=%d: Unknown", sig);
|
||||
return s;
|
||||
}
|
||||
|
||||
const char *get_home_dir()
|
||||
{
|
||||
const char *s = getenv("HOME");
|
||||
if (s)
|
||||
return s;
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
if (!pw)
|
||||
return NULL;
|
||||
return pw->pw_dir;
|
||||
}
|
||||
|
||||
void copy_file(const char *path_src, const char *path_dest)
|
||||
{
|
||||
|
||||
@@ -41,6 +41,18 @@ typedef enum MouseAction {
|
||||
|
||||
#define ALL_DESKTOPS 0xFFFFFFFF
|
||||
|
||||
void write_string(int fd, const char *s);
|
||||
void log_string(int fd, const char *s);
|
||||
|
||||
void dump_backtrace(int log_fd);
|
||||
|
||||
// sleep() returns early when signals arrive. This function does not.
|
||||
void safe_sleep(int seconds);
|
||||
|
||||
const char *signal_name(int sig);
|
||||
|
||||
const char *get_home_dir();
|
||||
|
||||
// Copies a file to another path
|
||||
void copy_file(const char *path_src, const char *path_dest);
|
||||
|
||||
|
||||
97
src/util/fps_distribution.c
Normal file
97
src/util/fps_distribution.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2017 tint2 authors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "fps_distribution.h"
|
||||
|
||||
static float *fps_distribution = NULL;
|
||||
|
||||
void init_fps_distribution()
|
||||
{
|
||||
// measure FPS with resolution:
|
||||
// 0-59: 1 (60 samples)
|
||||
// 60-199: 10 (14)
|
||||
// 200-1,999: 25 (72)
|
||||
// 1k-19,999: 1000 (19)
|
||||
// 20x+: inf (1)
|
||||
// => 166 samples
|
||||
if (fps_distribution)
|
||||
return;
|
||||
fps_distribution = calloc(170, sizeof(float));
|
||||
}
|
||||
|
||||
void cleanup_fps_distribution()
|
||||
{
|
||||
free(fps_distribution);
|
||||
fps_distribution = NULL;
|
||||
}
|
||||
|
||||
void sample_fps(double fps)
|
||||
{
|
||||
int fps_rounded = (int)(fps + 0.5);
|
||||
int i = 1;
|
||||
if (fps_rounded < 60) {
|
||||
i += fps_rounded;
|
||||
} else {
|
||||
i += 60;
|
||||
if (fps_rounded < 200) {
|
||||
i += (fps_rounded - 60) / 10;
|
||||
} else {
|
||||
i += 14;
|
||||
if (fps_rounded < 2000) {
|
||||
i += (fps_rounded - 200) / 25;
|
||||
} else {
|
||||
i += 72;
|
||||
if (fps_rounded < 20000) {
|
||||
i += (fps_rounded - 2000) / 1000;
|
||||
} else {
|
||||
i += 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// fprintf(stderr, "fps = %.0f => i = %d\n", fps, i);
|
||||
fps_distribution[i] += 1.;
|
||||
fps_distribution[0] += 1.;
|
||||
}
|
||||
|
||||
void fps_compute_stats(double *low, double *median, double *high, double *samples)
|
||||
{
|
||||
*median = *low = *high = *samples = -1;
|
||||
if (!fps_distribution || fps_distribution[0] < 1)
|
||||
return;
|
||||
float total = fps_distribution[0];
|
||||
*samples = (double)fps_distribution[0];
|
||||
float cum_low = 0.05f * total;
|
||||
float cum_median = 0.5f * total;
|
||||
float cum_high = 0.95f * total;
|
||||
float cum = 0;
|
||||
for (int i = 1; i <= 166; i++) {
|
||||
double value =
|
||||
(i < 60) ? i : (i < 74) ? (60 + (i - 60) * 10) : (i < 146) ? (200 + (i - 74) * 25)
|
||||
: (i < 165) ? (2000 + (i - 146) * 1000) : 20000;
|
||||
// fprintf(stderr, "%6.0f (i = %3d) : %.0f | ", value, i, (double)fps_distribution[i]);
|
||||
cum += fps_distribution[i];
|
||||
if (*low < 0 && cum >= cum_low)
|
||||
*low = value;
|
||||
if (*median < 0 && cum >= cum_median)
|
||||
*median = value;
|
||||
if (*high < 0 && cum >= cum_high)
|
||||
*high = value;
|
||||
}
|
||||
}
|
||||
9
src/util/fps_distribution.h
Normal file
9
src/util/fps_distribution.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef FPS_DISTRIBUTION_H
|
||||
#define FPS_DISTRIBUTION_H
|
||||
|
||||
void init_fps_distribution();
|
||||
void cleanup_fps_distribution();
|
||||
void sample_fps(double fps);
|
||||
void fps_compute_stats(double *low, double *median, double *high, double *samples);
|
||||
|
||||
#endif
|
||||
@@ -129,7 +129,7 @@ void change_timeout(timeout **t, int value_msec, int interval_msec, void (*_call
|
||||
}
|
||||
}
|
||||
|
||||
void update_next_timeout()
|
||||
struct timeval *get_next_timeout()
|
||||
{
|
||||
if (timeout_list) {
|
||||
timeout *t = timeout_list->data;
|
||||
@@ -145,9 +145,10 @@ void update_next_timeout()
|
||||
}
|
||||
} else
|
||||
next_timeout.tv_sec = -1;
|
||||
return (next_timeout.tv_sec >= 0 && next_timeout.tv_usec >= 0) ? &next_timeout : NULL;
|
||||
}
|
||||
|
||||
void callback_timeout_expired()
|
||||
void handle_expired_timers()
|
||||
{
|
||||
struct timespec cur_time;
|
||||
timeout *t;
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
// Periodic timeouts are aligned to each other whenever possible, i.e. one interval_msec is an
|
||||
// integral multiple of the other.
|
||||
|
||||
extern struct timeval next_timeout;
|
||||
typedef struct _timeout timeout;
|
||||
|
||||
// Initializes default global data.
|
||||
@@ -54,11 +53,12 @@ void change_timeout(timeout **t, int value_msec, int interval_msec, void (*_call
|
||||
// Stops the timer 't'
|
||||
void stop_timeout(timeout *t);
|
||||
|
||||
// Updates next_timeout to the value, when the next installed timeout will expire
|
||||
void update_next_timeout();
|
||||
// Get the time when the next installed timer will expire, or NULL if there is no timer.
|
||||
// Do not free the pointer; but it is safe to change its contents.
|
||||
struct timeval *get_next_timeout();
|
||||
|
||||
// Callback of all expired timeouts
|
||||
void callback_timeout_expired();
|
||||
void handle_expired_timers();
|
||||
|
||||
// Returns -1 if t1 < t2, 0 if t1 == t2, 1 if t1 > t2
|
||||
gint compare_timespecs(const struct timespec *t1, const struct timespec *t2);
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**************************************************************************/
|
||||
|
||||
#include "uevent.h"
|
||||
int uevent_fd = -1;
|
||||
|
||||
#ifdef ENABLE_UEVENT
|
||||
|
||||
#include <string.h>
|
||||
@@ -30,9 +33,7 @@
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "uevent.h"
|
||||
|
||||
static int ueventfd = -1;
|
||||
static struct sockaddr_nl nls;
|
||||
static GList *notifiers = NULL;
|
||||
|
||||
@@ -146,11 +147,11 @@ void uevent_unregister_notifier(struct uevent_notify *nb)
|
||||
|
||||
void uevent_handler()
|
||||
{
|
||||
if (ueventfd < 0)
|
||||
if (uevent_fd < 0)
|
||||
return;
|
||||
|
||||
char buf[512];
|
||||
int len = recv(ueventfd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
int len = recv(uevent_fd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
if (len < 0)
|
||||
return;
|
||||
|
||||
@@ -181,27 +182,27 @@ int uevent_init()
|
||||
nls.nl_groups = -1;
|
||||
|
||||
/* open socket */
|
||||
ueventfd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
|
||||
if (ueventfd < 0) {
|
||||
uevent_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
|
||||
if (uevent_fd < 0) {
|
||||
fprintf(stderr, "Error: socket open failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Listen to netlink socket */
|
||||
if (bind(ueventfd, (void *)&nls, sizeof(struct sockaddr_nl))) {
|
||||
if (bind(uevent_fd, (void *)&nls, sizeof(struct sockaddr_nl))) {
|
||||
fprintf(stderr, "Bind failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Kernel uevent interface initialized...\n");
|
||||
|
||||
return ueventfd;
|
||||
return uevent_fd;
|
||||
}
|
||||
|
||||
void uevent_cleanup()
|
||||
{
|
||||
if (ueventfd >= 0)
|
||||
close(ueventfd);
|
||||
if (uevent_fd >= 0)
|
||||
close(uevent_fd);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#ifndef UEVENT_H
|
||||
#define UEVENT_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
enum uevent_action {
|
||||
UEVENT_UNKNOWN = 0x01,
|
||||
UEVENT_ADD = 0x02,
|
||||
@@ -48,6 +50,8 @@ struct uevent_notify {
|
||||
void (*cb)(struct uevent *e, void *userdata);
|
||||
};
|
||||
|
||||
extern int uevent_fd;
|
||||
|
||||
#if ENABLE_UEVENT
|
||||
int uevent_init();
|
||||
void uevent_cleanup();
|
||||
|
||||
Reference in New Issue
Block a user