Skip to content

Commit 60d5f8d

Browse files
bretambroseJonathanHensonjustinboswell
authored
Stat (#526)
* Base statistics gathering and monitoring Co-authored-by: Jonathan M. Henson <jonathan.michael.henson@gmail.com> Co-authored-by: Justin Boswell <justin.boswell@gmail.com>
1 parent 9ef00f4 commit 60d5f8d

File tree

7 files changed

+252
-34
lines changed

7 files changed

+252
-34
lines changed

include/aws/common/error.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,18 @@
1919
#include <aws/common/assert.h>
2020
#include <aws/common/exports.h>
2121
#include <aws/common/macros.h>
22+
#include <aws/common/package.h>
2223
#include <aws/common/stdint.h>
2324

2425
#define AWS_OP_SUCCESS (0)
2526
#define AWS_OP_ERR (-1)
2627

28+
/* Each library gets space for 2^^10 error entries */
29+
#define AWS_ERROR_ENUM_STRIDE_BITS 10
30+
#define AWS_ERROR_ENUM_STRIDE (1U << AWS_ERROR_ENUM_STRIDE_BITS)
31+
#define AWS_ERROR_ENUM_BEGIN_RANGE(x) ((x)*AWS_ERROR_ENUM_STRIDE)
32+
#define AWS_ERROR_ENUM_END_RANGE(x) (((x) + 1) * AWS_ERROR_ENUM_STRIDE - 1)
33+
2734
struct aws_error_info {
2835
int error_code;
2936
const char *literal_name;
@@ -144,7 +151,7 @@ int aws_translate_and_raise_io_error(int error_no);
144151
AWS_EXTERN_C_END
145152

146153
enum aws_common_error {
147-
AWS_ERROR_SUCCESS = 0,
154+
AWS_ERROR_SUCCESS = AWS_ERROR_ENUM_BEGIN_RANGE(AWS_C_COMMON_PACKAGE_ID),
148155
AWS_ERROR_OOM,
149156
AWS_ERROR_UNKNOWN,
150157
AWS_ERROR_SHORT_BUFFER,
@@ -193,7 +200,7 @@ enum aws_common_error {
193200
AWS_ERROR_C_STRING_BUFFER_NOT_NULL_TERMINATED,
194201
AWS_ERROR_STRING_MATCH_NOT_FOUND,
195202

196-
AWS_ERROR_END_COMMON_RANGE = 0x03FF
203+
AWS_ERROR_END_COMMON_RANGE = AWS_ERROR_ENUM_END_RANGE(AWS_C_COMMON_PACKAGE_ID)
197204
};
198205

199206
#endif /* AWS_COMMON_ERROR_H */

include/aws/common/logging.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,11 @@ enum aws_log_level {
6464
*/
6565
typedef uint32_t aws_log_subject_t;
6666

67-
#define AWS_LOG_SUBJECT_BIT_SPACE 10
68-
#define AWS_LOG_SUBJECT_SPACE_SIZE (1 << AWS_LOG_SUBJECT_BIT_SPACE)
69-
#define AWS_LOG_SUBJECT_SPACE_MASK (AWS_LOG_SUBJECT_SPACE_SIZE - 1)
67+
/* Each library gets space for 2^^10 log subject entries */
68+
#define AWS_LOG_SUBJECT_STRIDE_BITS 10
69+
#define AWS_LOG_SUBJECT_STRIDE (1U << AWS_LOG_SUBJECT_STRIDE_BITS)
70+
#define AWS_LOG_SUBJECT_BEGIN_RANGE(x) ((x)*AWS_LOG_SUBJECT_STRIDE)
71+
#define AWS_LOG_SUBJECT_END_RANGE(x) (((x) + 1) * AWS_LOG_SUBJECT_STRIDE - 1)
7072

7173
struct aws_log_subject_info {
7274
aws_log_subject_t subject_id;
@@ -83,11 +85,11 @@ struct aws_log_subject_info_list {
8385
};
8486

8587
enum aws_common_log_subject {
86-
AWS_LS_COMMON_GENERAL = 0,
88+
AWS_LS_COMMON_GENERAL = AWS_LOG_SUBJECT_BEGIN_RANGE(AWS_C_COMMON_PACKAGE_ID),
8789
AWS_LS_COMMON_TASK_SCHEDULER,
8890
AWS_LS_COMMON_MEMTRACE,
8991

90-
AWS_LS_COMMON_LAST = (AWS_LS_COMMON_GENERAL + AWS_LOG_SUBJECT_SPACE_SIZE - 1)
92+
AWS_LS_COMMON_LAST = AWS_LOG_SUBJECT_END_RANGE(AWS_C_COMMON_PACKAGE_ID)
9193
};
9294

9395
struct aws_logger;

include/aws/common/package.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#ifndef AWS_COMMON_PACKAGE_H
2+
#define AWS_COMMON_PACKAGE_H
3+
4+
/*
5+
* Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License").
8+
* You may not use this file except in compliance with the License.
9+
* A copy of the License is located at
10+
*
11+
* http://aws.amazon.com/apache2.0
12+
*
13+
* or in the "license" file accompanying this file. This file is distributed
14+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
15+
* express or implied. See the License for the specific language governing
16+
* permissions and limitations under the License.
17+
*/
18+
19+
/*
20+
* Preliminary cap on the number of possible aws-c-libraries participating in shared enum ranges for
21+
* errors, log subjects, and other cross-library enums. Expandable as needed
22+
*/
23+
#define AWS_PACKAGE_SLOTS 16
24+
25+
/*
26+
* Each aws-c-* and aws-crt-* library has a unique package id starting from zero. These are used to macro-calculate
27+
* correct ranges for the cross-library enumerations.
28+
*/
29+
#define AWS_C_COMMON_PACKAGE_ID 0
30+
31+
#endif /* AWS_COMMON_PACKAGE_H */

include/aws/common/statistics.h

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#ifndef AWS_COMMON_STATISTICS_H
2+
#define AWS_COMMON_STATISTICS_H
3+
4+
/*
5+
* Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License").
8+
* You may not use this file except in compliance with the License.
9+
* A copy of the License is located at
10+
*
11+
* http://aws.amazon.com/apache2.0
12+
*
13+
* or in the "license" file accompanying this file. This file is distributed
14+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
15+
* expressaws_crt_statistics_base or implied. See the License for the specific language governing
16+
* permissions and limitations under the License.
17+
*/
18+
19+
#include <aws/common/common.h>
20+
#include <aws/common/package.h>
21+
22+
#include <aws/common/stdint.h>
23+
24+
struct aws_array_list;
25+
26+
typedef uint32_t aws_crt_statistics_category_t;
27+
28+
/* Each library gets space for 2^^8 category entries */
29+
#define AWS_CRT_STATISTICS_CATEGORY_STRIDE_BITS 8
30+
#define AWS_CRT_STATISTICS_CATEGORY_STRIDE (1U << AWS_CRT_STATISTICS_CATEGORY_STRIDE_BITS)
31+
#define AWS_CRT_STATISTICS_CATEGORY_BEGIN_RANGE(x) ((x)*AWS_CRT_STATISTICS_CATEGORY_STRIDE)
32+
#define AWS_CRT_STATISTICS_CATEGORY_END_RANGE(x) (((x) + 1) * AWS_CRT_STATISTICS_CATEGORY_STRIDE - 1)
33+
34+
/**
35+
* The common-specific range of the aws_crt_statistics_category cross-library enum.
36+
*
37+
* This enum functions as an RTTI value that lets statistics handler's interpret (via cast) a
38+
* specific statistics structure if the RTTI value is understood.
39+
*
40+
* Common doesn't have any statistics structures presently, so its range is essentially empty.
41+
*
42+
*/
43+
enum aws_crt_common_statistics_category {
44+
AWSCRT_STAT_CAT_INVALID = AWS_CRT_STATISTICS_CATEGORY_BEGIN_RANGE(AWS_C_COMMON_PACKAGE_ID)
45+
};
46+
47+
/**
48+
* Pattern-struct that functions as a base "class" for all statistics structures. To conform
49+
* to the pattern, a statistics structure must have its first member be the category. In that
50+
* case it becomes "safe" to cast from aws_crt_statistics_base to the specific statistics structure
51+
* based on the category value.
52+
*/
53+
struct aws_crt_statistics_base {
54+
aws_crt_statistics_category_t category;
55+
};
56+
57+
/**
58+
* The start and end time, in milliseconds-since-epoch, that a set of statistics was gathered over.
59+
*/
60+
struct aws_crt_statistics_sample_interval {
61+
uint64_t begin_time_ms;
62+
uint64_t end_time_ms;
63+
};
64+
65+
struct aws_crt_statistics_handler;
66+
67+
/*
68+
* Statistics intake function. The array_list is a list of pointers to aws_crt_statistics_base "derived" (via
69+
* pattern) objects. The handler should iterate the list and downcast elements whose RTTI category it understands,
70+
* while skipping those it does not understand.
71+
*/
72+
typedef void(aws_crt_statistics_handler_process_statistics_fn)(
73+
struct aws_crt_statistics_handler *handler,
74+
struct aws_crt_statistics_sample_interval *interval,
75+
struct aws_array_list *stats,
76+
void *context);
77+
78+
/*
79+
* Destroys a statistics handler implementation
80+
*/
81+
typedef void(aws_crt_statistics_handler_destroy_fn)(struct aws_crt_statistics_handler *handler);
82+
83+
/*
84+
* The period, in milliseconds, that the handler would like to be informed of statistics. Statistics generators are
85+
* not required to honor this value, but should if able.
86+
*/
87+
typedef uint64_t(aws_crt_statistics_handler_get_report_interval_ms_fn)(struct aws_crt_statistics_handler *);
88+
89+
/**
90+
* Vtable for functions that all statistics handlers must implement
91+
*/
92+
struct aws_crt_statistics_handler_vtable {
93+
aws_crt_statistics_handler_process_statistics_fn *process_statistics;
94+
aws_crt_statistics_handler_destroy_fn *destroy;
95+
aws_crt_statistics_handler_get_report_interval_ms_fn *get_report_interval_ms;
96+
};
97+
98+
/**
99+
* Base structure for all statistics handler implementations.
100+
*
101+
* A statistics handler is an object that listens to a stream of polymorphic (via the category RTTI enum) statistics
102+
* structures emitted from some arbitrary source. In the initial implementation, statistics handlers are primarily
103+
* attached to channels, where they monitor IO throughput and state data (from channel handlers) to determine a
104+
* connection's health.
105+
*
106+
* Statistics handlers are a generalization of the timeout and bandwidth filters that are often associated with
107+
* SDK network connections. Configurable, default implementations are defined at the protocol level (http, etc...)
108+
* where they can be attached at connection (channel) creation time.
109+
*/
110+
struct aws_crt_statistics_handler {
111+
struct aws_crt_statistics_handler_vtable *vtable;
112+
struct aws_allocator *allocator;
113+
void *impl;
114+
};
115+
116+
AWS_EXTERN_C_BEGIN
117+
118+
/**
119+
* Submits a list of statistics objects to a statistics handler for processing
120+
*
121+
* handler - the statistics handler that will process the statistics objects
122+
* interval - time period over which the statistics were gathered
123+
* stats - list of pointers to structures that can be case to aws_crt_statistics_base (i.e. have category as a first
124+
* member)
125+
* context - (optional) additional context specific to where the statistics handler has been attached
126+
*/
127+
AWS_COMMON_API
128+
void aws_crt_statistics_handler_process_statistics(
129+
struct aws_crt_statistics_handler *handler,
130+
struct aws_crt_statistics_sample_interval *interval,
131+
struct aws_array_list *stats,
132+
void *context);
133+
134+
/**
135+
* Queries the frequency (via an interval in milliseconds) which a statistics handler would like to be informed
136+
* of statistics.
137+
*/
138+
AWS_COMMON_API
139+
uint64_t aws_crt_statistics_handler_get_report_interval_ms(struct aws_crt_statistics_handler *handler);
140+
141+
/**
142+
* completely destroys a statistics handler. The handler's cleanup function must clean up the impl portion completely
143+
* (including its allocation, if done separately).
144+
*/
145+
AWS_COMMON_API
146+
void aws_crt_statistics_handler_destroy(struct aws_crt_statistics_handler *handler);
147+
148+
AWS_EXTERN_C_END
149+
150+
#endif /* AWS_COMMON_STATISTICS_H */

source/error.c

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,15 @@ static void *s_global_error_context = NULL;
2929
static AWS_THREAD_LOCAL aws_error_handler_fn *tl_thread_handler = NULL;
3030
AWS_THREAD_LOCAL void *tl_thread_handler_context = NULL;
3131

32-
#ifndef AWS_MAX_ERROR_SLOTS
33-
# define AWS_MAX_ERROR_SLOTS 16
34-
#endif
35-
3632
/* Since slot size is 00000100 00000000, to divide, we need to shift right by 10
3733
* bits to find the slot, and to find the modulus, we use a binary and with
38-
* 00000011 11111111 to find the index in that slot. The next three values
39-
* define those constants */
40-
#define AWS_ERROR_SLOT_SIZE 0x0400
41-
#define SLOT_DIV_SHIFT 0x0A
42-
#define SLOT_MASK 0x03FF
34+
* 00000011 11111111 to find the index in that slot.
35+
*/
36+
#define SLOT_MASK (AWS_ERROR_ENUM_STRIDE - 1)
4337

44-
static const int MAX_ERROR_CODE = AWS_ERROR_SLOT_SIZE * AWS_MAX_ERROR_SLOTS;
38+
static const int MAX_ERROR_CODE = AWS_ERROR_ENUM_STRIDE * AWS_PACKAGE_SLOTS;
4539

46-
static const struct aws_error_info_list *volatile ERROR_SLOTS[AWS_MAX_ERROR_SLOTS] = {0};
40+
static const struct aws_error_info_list *volatile ERROR_SLOTS[AWS_PACKAGE_SLOTS] = {0};
4741

4842
int aws_last_error(void) {
4943
return tl_last_error;
@@ -54,8 +48,8 @@ static const struct aws_error_info *get_error_by_code(int err) {
5448
return NULL;
5549
}
5650

57-
int slot_index = err >> SLOT_DIV_SHIFT;
58-
int error_index = err & SLOT_MASK;
51+
uint32_t slot_index = (uint32_t)err >> AWS_ERROR_ENUM_STRIDE_BITS;
52+
uint32_t error_index = (uint32_t)err & SLOT_MASK;
5953

6054
const struct aws_error_info_list *error_slot = ERROR_SLOTS[slot_index];
6155

@@ -151,9 +145,9 @@ void aws_register_error_info(const struct aws_error_info_list *error_info) {
151145
AWS_FATAL_ASSERT(error_info->count);
152146

153147
const int min_range = error_info->error_list[0].error_code;
154-
const int slot_index = min_range >> SLOT_DIV_SHIFT;
148+
const int slot_index = min_range >> AWS_ERROR_ENUM_STRIDE_BITS;
155149

156-
if (slot_index >= AWS_MAX_ERROR_SLOTS || slot_index < 0) {
150+
if (slot_index >= AWS_PACKAGE_SLOTS || slot_index < 0) {
157151
/* This is an NDEBUG build apparently. Kill the process rather than
158152
* corrupting heap. */
159153
fprintf(stderr, "Bad error slot index %d\n", slot_index);
@@ -185,9 +179,9 @@ void aws_unregister_error_info(const struct aws_error_info_list *error_info) {
185179
AWS_FATAL_ASSERT(error_info->count);
186180

187181
const int min_range = error_info->error_list[0].error_code;
188-
const int slot_index = min_range >> SLOT_DIV_SHIFT;
182+
const int slot_index = min_range >> AWS_ERROR_ENUM_STRIDE_BITS;
189183

190-
if (slot_index >= AWS_MAX_ERROR_SLOTS || slot_index < 0) {
184+
if (slot_index >= AWS_PACKAGE_SLOTS || slot_index < 0) {
191185
/* This is an NDEBUG build apparently. Kill the process rather than
192186
* corrupting heap. */
193187
fprintf(stderr, "Bad error slot index %d\n", slot_index);

source/logging.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -310,20 +310,18 @@ int aws_thread_id_t_to_string(aws_thread_id_t thread_id, char *buffer, size_t bu
310310
return AWS_OP_SUCCESS;
311311
}
312312

313-
#ifndef AWS_MAX_LOG_SUBJECT_SLOTS
314-
# define AWS_MAX_LOG_SUBJECT_SLOTS 16u
315-
#endif
313+
#define AWS_LOG_SUBJECT_SPACE_MASK (AWS_LOG_SUBJECT_STRIDE - 1)
316314

317-
static const uint32_t S_MAX_LOG_SUBJECT = AWS_LOG_SUBJECT_SPACE_SIZE * AWS_MAX_LOG_SUBJECT_SLOTS - 1;
315+
static const uint32_t S_MAX_LOG_SUBJECT = AWS_LOG_SUBJECT_STRIDE_BITS * AWS_PACKAGE_SLOTS - 1;
318316

319-
static const struct aws_log_subject_info_list *volatile s_log_subject_slots[AWS_MAX_LOG_SUBJECT_SLOTS] = {0};
317+
static const struct aws_log_subject_info_list *volatile s_log_subject_slots[AWS_PACKAGE_SLOTS] = {0};
320318

321319
static const struct aws_log_subject_info *s_get_log_subject_info_by_id(aws_log_subject_t subject) {
322320
if (subject > S_MAX_LOG_SUBJECT) {
323321
return NULL;
324322
}
325323

326-
uint32_t slot_index = subject >> AWS_LOG_SUBJECT_BIT_SPACE;
324+
uint32_t slot_index = subject >> AWS_LOG_SUBJECT_STRIDE_BITS;
327325
uint32_t subject_index = subject & AWS_LOG_SUBJECT_SPACE_MASK;
328326

329327
const struct aws_log_subject_info_list *subject_slot = s_log_subject_slots[slot_index];
@@ -356,9 +354,9 @@ void aws_register_log_subject_info_list(struct aws_log_subject_info_list *log_su
356354
AWS_FATAL_ASSERT(log_subject_list->count);
357355

358356
const uint32_t min_range = log_subject_list->subject_list[0].subject_id;
359-
const uint32_t slot_index = min_range >> AWS_LOG_SUBJECT_BIT_SPACE;
357+
const uint32_t slot_index = min_range >> AWS_LOG_SUBJECT_STRIDE_BITS;
360358

361-
if (slot_index >= AWS_MAX_LOG_SUBJECT_SLOTS) {
359+
if (slot_index >= AWS_PACKAGE_SLOTS) {
362360
/* This is an NDEBUG build apparently. Kill the process rather than
363361
* corrupting heap. */
364362
fprintf(stderr, "Bad log subject slot index 0x%016x\n", slot_index);
@@ -379,9 +377,9 @@ void aws_unregister_log_subject_info_list(struct aws_log_subject_info_list *log_
379377
AWS_FATAL_ASSERT(log_subject_list->count);
380378

381379
const uint32_t min_range = log_subject_list->subject_list[0].subject_id;
382-
const uint32_t slot_index = min_range >> AWS_LOG_SUBJECT_BIT_SPACE;
380+
const uint32_t slot_index = min_range >> AWS_LOG_SUBJECT_STRIDE_BITS;
383381

384-
if (slot_index >= AWS_MAX_LOG_SUBJECT_SLOTS) {
382+
if (slot_index >= AWS_PACKAGE_SLOTS) {
385383
/* This is an NDEBUG build apparently. Kill the process rather than
386384
* corrupting heap. */
387385
fprintf(stderr, "Bad log subject slot index 0x%016x\n", slot_index);

source/statistics.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
#include <aws/common/statistics.h>
17+
18+
void aws_crt_statistics_handler_process_statistics(
19+
struct aws_crt_statistics_handler *handler,
20+
struct aws_crt_statistics_sample_interval *interval,
21+
struct aws_array_list *stats,
22+
void *context) {
23+
handler->vtable->process_statistics(handler, interval, stats, context);
24+
}
25+
26+
uint64_t aws_crt_statistics_handler_get_report_interval_ms(struct aws_crt_statistics_handler *handler) {
27+
return handler->vtable->get_report_interval_ms(handler);
28+
}
29+
30+
void aws_crt_statistics_handler_destroy(struct aws_crt_statistics_handler *handler) {
31+
if (handler == NULL) {
32+
return;
33+
}
34+
35+
handler->vtable->destroy(handler);
36+
}

0 commit comments

Comments
 (0)