diff --git a/Makefile b/Makefile index a5269db0b..73f7dd40a 100644 --- a/Makefile +++ b/Makefile @@ -943,7 +943,7 @@ OBJS = src/proto_http.o src/cfgparse-listen.o src/proto_htx.o src/stream.o \ src/http.o src/hpack-dec.o src/action.o src/proto_udp.o src/http_acl.o \ src/xxhash.o src/hpack-enc.o src/h2.o src/freq_ctr.o src/lru.o \ src/protocol.o src/arg.o src/hpack-huff.o src/hdr_idx.o src/base64.o \ - src/hash.o src/mailers.o + src/hash.o src/mailers.o src/activity.o EBTREE_OBJS = $(EBTREE_DIR)/ebtree.o $(EBTREE_DIR)/eb32sctree.o \ $(EBTREE_DIR)/eb32tree.o $(EBTREE_DIR)/eb64tree.o \ diff --git a/include/common/time.h b/include/common/time.h index a1664b491..b9efd714b 100644 --- a/include/common/time.h +++ b/include/common/time.h @@ -85,11 +85,6 @@ REGPRM2 int tv_ms_cmp(const struct timeval *tv1, const struct timeval *tv2); */ REGPRM2 int tv_ms_cmp2(const struct timeval *tv1, const struct timeval *tv2); -/* Updates the current thread's statistics about stolen CPU time. The unit for - * is half-milliseconds. - */ -REGPRM1 void report_stolen_time(uint64_t stolen); - /**** general purpose functions and macros *******************************/ @@ -581,26 +576,6 @@ static inline void measure_idle() */ static inline void tv_entering_poll() { - uint64_t new_mono_time; - uint64_t new_cpu_time; - int64_t stolen; - - new_cpu_time = now_cpu_time(); - new_mono_time = now_mono_time(); - - if (prev_cpu_time && prev_mono_time) { - new_cpu_time -= prev_cpu_time; - new_mono_time -= prev_mono_time; - stolen = new_mono_time - new_cpu_time; - if (stolen >= 500000) { - stolen /= 500000; - /* more than half a millisecond difference might - * indicate an undesired preemption. - */ - report_stolen_time(stolen); - } - } - gettimeofday(&before_poll, NULL); } diff --git a/include/proto/activity.h b/include/proto/activity.h new file mode 100644 index 000000000..4cf9c8d49 --- /dev/null +++ b/include/proto/activity.h @@ -0,0 +1,69 @@ +/* + * include/proto/activity.h + * This file contains macros and inline functions for activity measurements. + * + * Copyright (C) 2000-2018 Willy Tarreau - w@1wt.eu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, version 2.1 + * exclusively. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _PROTO_ACTIVITY_H +#define _PROTO_ACTIVITY_H + +#include +#include +#include +#include + +extern struct activity activity[MAX_THREADS]; + + +void report_stolen_time(uint64_t stolen); + +/* Collect date and time information before calling poll(). This will be used + * to count the run time of the past loop and the sleep time of the next poll. + */ +static inline void activity_count_runtime() +{ + uint64_t new_mono_time; + uint64_t new_cpu_time; + int64_t stolen; + + new_cpu_time = now_cpu_time(); + new_mono_time = now_mono_time(); + + if (prev_cpu_time && prev_mono_time) { + new_cpu_time -= prev_cpu_time; + new_mono_time -= prev_mono_time; + stolen = new_mono_time - new_cpu_time; + if (unlikely(stolen >= 500000)) { + stolen /= 500000; + /* more than half a millisecond difference might + * indicate an undesired preemption. + */ + report_stolen_time(stolen); + } + } +} + + +#endif /* _PROTO_ACTIVITY_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */ diff --git a/include/proto/fd.h b/include/proto/fd.h index 03e318284..81aea87bc 100644 --- a/include/proto/fd.h +++ b/include/proto/fd.h @@ -30,9 +30,8 @@ #include #include #include - #include -#include +#include /* public variables */ diff --git a/include/types/activity.h b/include/types/activity.h new file mode 100644 index 000000000..99922b4a8 --- /dev/null +++ b/include/types/activity.h @@ -0,0 +1,63 @@ +/* + * include/types/activity.h + * This file contains structure declarations for activity measurements. + * + * Copyright (C) 2000-2018 Willy Tarreau - w@1wt.eu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, version 2.1 + * exclusively. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _TYPES_ACTIVITY_H +#define _TYPES_ACTIVITY_H + +#include +#include + +/* per-thread activity reports. It's important that it's aligned on cache lines + * because some elements will be updated very often. Most counters are OK on + * 32-bit since this will be used during debugging sessions for troubleshooting + * in iterative mode. + */ +struct activity { + unsigned int loops; // complete loops in run_poll_loop() + unsigned int wake_cache; // active fd_cache prevented poll() from sleeping + unsigned int wake_tasks; // active tasks prevented poll() from sleeping + unsigned int wake_signal; // pending signal prevented poll() from sleeping + unsigned int poll_exp; // number of times poll() sees an expired timeout (includes wake_*) + unsigned int poll_drop; // poller dropped a dead FD from the update list + unsigned int poll_dead; // poller woke up with a dead FD + unsigned int poll_skip; // poller skipped another thread's FD + unsigned int fd_skip; // fd cache skipped another thread's FD + unsigned int fd_lock; // fd cache skipped a locked FD + unsigned int fd_del; // fd cache detected a deleted FD + unsigned int conn_dead; // conn_fd_handler woke up on an FD indicating a dead connection + unsigned int stream; // calls to process_stream() + unsigned int empty_rq; // calls to process_runnable_tasks() with nothing for the thread + unsigned int long_rq; // process_runnable_tasks() left with tasks in the run queue + unsigned int cpust_total; // sum of half-ms stolen per thread + struct freq_ctr cpust_1s; // avg amount of half-ms stolen over last second + struct freq_ctr_period cpust_15s; // avg amount of half-ms stolen over last 15s + char __pad[0]; // unused except to check remaining room + char __end[0] __attribute__((aligned(64))); // align size to 64. +}; + +#endif /* _TYPES_ACTIVITY_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */ diff --git a/include/types/global.h b/include/types/global.h index 7c6f95420..5a3f338a4 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -28,7 +28,6 @@ #include #include -#include #include #include #include @@ -177,34 +176,6 @@ struct global { #endif }; -/* per-thread activity reports. It's important that it's aligned on cache lines - * because some elements will be updated very often. Most counters are OK on - * 32-bit since this will be used during debugging sessions for troubleshooting - * in iterative mode. - */ -struct activity { - unsigned int loops; // complete loops in run_poll_loop() - unsigned int wake_cache; // active fd_cache prevented poll() from sleeping - unsigned int wake_tasks; // active tasks prevented poll() from sleeping - unsigned int wake_signal; // pending signal prevented poll() from sleeping - unsigned int poll_exp; // number of times poll() sees an expired timeout (includes wake_*) - unsigned int poll_drop; // poller dropped a dead FD from the update list - unsigned int poll_dead; // poller woke up with a dead FD - unsigned int poll_skip; // poller skipped another thread's FD - unsigned int fd_skip; // fd cache skipped another thread's FD - unsigned int fd_lock; // fd cache skipped a locked FD - unsigned int fd_del; // fd cache detected a deleted FD - unsigned int conn_dead; // conn_fd_handler woke up on an FD indicating a dead connection - unsigned int stream; // calls to process_stream() - unsigned int empty_rq; // calls to process_runnable_tasks() with nothing for the thread - unsigned int long_rq; // process_runnable_tasks() left with tasks in the run queue - unsigned int cpust_total; // sum of half-ms stolen per thread - struct freq_ctr cpust_1s; // avg amount of half-ms stolen over last second - struct freq_ctr_period cpust_15s; // avg amount of half-ms stolen over last 15s - char __pad[0]; // unused except to check remaining room - char __end[0] __attribute__((aligned(64))); // align size to 64. -}; - /* * Structure used to describe the processes in master worker mode */ @@ -221,7 +192,6 @@ struct mworker_proc { }; extern struct global global; -extern struct activity activity[MAX_THREADS]; extern int pid; /* current process id */ extern int relative_pid; /* process id starting at 1 */ extern unsigned long pid_bit; /* bit corresponding to the process id */ diff --git a/src/activity.c b/src/activity.c new file mode 100644 index 000000000..c843b47fd --- /dev/null +++ b/src/activity.c @@ -0,0 +1,31 @@ +/* + * activity measurement functions. + * + * Copyright 2000-2018 Willy Tarreau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include + +/* One struct per thread containing all collected measurements */ +struct activity activity[MAX_THREADS] __attribute__((aligned(64))) = { }; + + +/* Updates the current thread's statistics about stolen CPU time. The unit for + * is half-milliseconds. + */ +void report_stolen_time(uint64_t stolen) +{ + activity[tid].cpust_total += stolen; + update_freq_ctr(&activity[tid].cpust_1s, stolen); + update_freq_ctr_period(&activity[tid].cpust_15s, 15000, stolen); +} diff --git a/src/cli.c b/src/cli.c index ef58ba616..f0bba331e 100644 --- a/src/cli.c +++ b/src/cli.c @@ -45,6 +45,7 @@ #include #include +#include #include #include #include diff --git a/src/ev_epoll.c b/src/ev_epoll.c index 9d111ce65..a9f96ab80 100644 --- a/src/ev_epoll.c +++ b/src/ev_epoll.c @@ -25,6 +25,7 @@ #include +#include #include @@ -147,6 +148,7 @@ REGPRM2 static void _do_poll(struct poller *p, int exp) /* now let's wait for polled events */ wait_time = compute_poll_timeout(exp); tv_entering_poll(); + activity_count_runtime(); status = epoll_wait(epoll_fd[tid], epoll_events, global.tune.maxpollevents, wait_time); tv_leaving_poll(wait_time, status); diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c index c1c3e1164..dc1310cff 100644 --- a/src/ev_kqueue.c +++ b/src/ev_kqueue.c @@ -26,6 +26,7 @@ #include +#include #include @@ -135,6 +136,7 @@ REGPRM2 static void _do_poll(struct poller *p, int exp) timeout.tv_nsec = (delta_ms % 1000) * 1000000; fd = global.tune.maxpollevents; tv_entering_poll(); + activity_count_runtime(); status = kevent(kqueue_fd[tid], // int kq NULL, // const struct kevent *changelist 0, // int nchanges diff --git a/src/ev_poll.c b/src/ev_poll.c index b08274ccc..ce5e38f96 100644 --- a/src/ev_poll.c +++ b/src/ev_poll.c @@ -25,6 +25,7 @@ #include +#include #include @@ -195,6 +196,7 @@ REGPRM2 static void _do_poll(struct poller *p, int exp) /* now let's wait for events */ wait_time = compute_poll_timeout(exp); tv_entering_poll(); + activity_count_runtime(); status = poll(poll_events, nbfd, wait_time); tv_leaving_poll(wait_time, status); diff --git a/src/ev_select.c b/src/ev_select.c index 464635b0f..f435813aa 100644 --- a/src/ev_select.c +++ b/src/ev_select.c @@ -22,6 +22,7 @@ #include +#include #include @@ -165,6 +166,7 @@ REGPRM2 static void _do_poll(struct poller *p, int exp) delta.tv_sec = (delta_ms / 1000); delta.tv_usec = (delta_ms % 1000) * 1000; tv_entering_poll(); + activity_count_runtime(); status = select(maxfd, readnotnull ? tmp_evts[DIR_RD] : NULL, writenotnull ? tmp_evts[DIR_WR] : NULL, diff --git a/src/haproxy.c b/src/haproxy.c index 79de01b06..b8337b313 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -93,6 +93,7 @@ #include #include +#include #include #include #include @@ -170,8 +171,6 @@ struct global global = { /* others NULL OK */ }; -struct activity activity[MAX_THREADS] __attribute__((aligned(64))) = { }; - /*********************************************************************/ int stopping; /* non zero means stopping in progress */ diff --git a/src/stream.c b/src/stream.c index 41555544c..3c84cbe6b 100644 --- a/src/stream.c +++ b/src/stream.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include diff --git a/src/time.c b/src/time.c index b404b2581..8f9b94341 100644 --- a/src/time.c +++ b/src/time.c @@ -18,8 +18,6 @@ #include #include #include -#include -#include THREAD_LOCAL unsigned int ms_left_scaled; /* milliseconds left for current second (0..2^32-1) */ THREAD_LOCAL unsigned int now_ms; /* internal date in milliseconds (may wrap) */ @@ -264,16 +262,6 @@ REGPRM2 void tv_update_date(int max_wait, int interrupted) return; } -/* Updates the current thread's statistics about stolen CPU time. The unit for - * is half-milliseconds. - */ -REGPRM1 void report_stolen_time(uint64_t stolen) -{ - activity[tid].cpust_total += stolen; - update_freq_ctr(&activity[tid].cpust_1s, stolen); - update_freq_ctr_period(&activity[tid].cpust_15s, 15000, stolen); -} - /* * Local variables: * c-indent-level: 8