summaryrefslogtreecommitdiffstats
path: root/plugins/solidigm/solidigm-telemetry/nlog.c
blob: 926772b26cdce4734a27d3bc2ee4ebd2c4c17775 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// SPDX-License-Identifier: MIT
/*
 * Copyright (c) 2023 Solidigm.
 *
 * Author: leonardo.da.cunha@solidigm.com
 */

#include "nlog.h"
#include "config.h"
#include <string.h>
#include <stdio.h>

#include "ccan/ilog/ilog.h"

#define LOG_ENTRY_HEADER_SIZE 1
#define LOG_ENTRY_TIMESTAMP_SIZE 2
#define LOG_ENTRY_NUM_ARGS_MAX 8
#define LOG_ENTRY_MAX_SIZE (LOG_ENTRY_HEADER_SIZE + LOG_ENTRY_TIMESTAMP_SIZE + \
			    LOG_ENTRY_NUM_ARGS_MAX)
#define NUM_ARGS_MASK ((1 << ((int)STATIC_ILOG_32(LOG_ENTRY_NUM_ARGS_MAX))) - 1)
#define MAX_HEADER_MISMATCH_TRACK 10

static int formats_find(struct json_object *formats, uint32_t val, struct json_object **format)
{
	char hex_header[STR_HEX32_SIZE];

	snprintf(hex_header, STR_HEX32_SIZE, "0x%08X", val);
	return json_object_object_get_ex(formats, hex_header, format);
}

static uint32_t nlog_get_pos(const uint32_t *nlog, const uint32_t nlog_size, int pos)
{
	return nlog[pos % nlog_size];
}

static uint32_t nlog_get_events(const uint32_t *nlog, const uint32_t nlog_size, int start_offset,
	       struct json_object *formats, struct json_object *events, uint32_t *tail_mismatches)
{
	uint32_t event_count = 0;
	int last_bad_header_pos = nlog_size + 1; // invalid nlog offset
	uint32_t tail_count = 0;

	for (int i = nlog_size - start_offset - 1; i >= -start_offset; i--) {
		struct json_object *format;
		uint32_t header = nlog_get_pos(nlog, nlog_size, i);
		uint32_t num_data;

		if (header == 0 || !formats_find(formats, header, &format)) {
			if (event_count > 0) {
				//check if fould circular buffer tail
				if (i != (last_bad_header_pos - 1)) {
					if (tail_mismatches &&
					    (tail_count < MAX_HEADER_MISMATCH_TRACK))
						tail_mismatches[tail_count] = header;
					tail_count++;
				}
				last_bad_header_pos = i;
			}
			continue;
		}
		num_data = header & NUM_ARGS_MASK;
		if (events) {
			struct json_object *event = json_object_new_array();
			struct json_object *param = json_object_new_array();
			uint32_t val = nlog_get_pos(nlog, nlog_size, i - 1);

			json_object_array_add(events, event);
			json_object_array_add(event, json_object_new_int64(val));
			val = nlog_get_pos(nlog, nlog_size, i - 2);
			json_object_array_add(event, json_object_new_int64(val));
			json_object_array_add(event, json_object_new_int64(header));
			json_object_array_add(event, param);
			for (uint32_t j = 0; j < num_data; j++) {
				val = nlog_get_pos(nlog, nlog_size, i - 3 - j);
				json_object_array_add(param, json_object_new_int64(val));
			}
			json_object_get(format);
			json_object_array_add(event, format);
		}
		i -= 2 + num_data;
		event_count++;
	}
	return tail_count;
}

int solidigm_nlog_parse(const char *buffer, uint64_t buff_size,	struct json_object *formats,
			struct json_object *metadata, struct json_object *output)
{
	uint32_t smaller_tail_count = UINT32_MAX;
	int best_offset = 0;
	uint32_t offset_tail_mismatches[LOG_ENTRY_MAX_SIZE][MAX_HEADER_MISMATCH_TRACK];
	struct json_object *events = json_object_new_array();
	const uint32_t *nlog = (uint32_t *)buffer;
	const uint32_t nlog_size = buff_size / sizeof(uint32_t);

	for (int i = 0; i < LOG_ENTRY_MAX_SIZE; i++) {
		uint32_t tail_count = nlog_get_events(nlog, nlog_size, i, formats, NULL,
						      offset_tail_mismatches[i]);
		if (tail_count < smaller_tail_count) {
			best_offset = i;
			smaller_tail_count = tail_count;
		}
		if (tail_count == 0)
			break;
	}
	if (smaller_tail_count > 1) {
		const char *name = "";
		int media_bank = -1;
		char str_mismatches[(STR_HEX32_SIZE + 1) * MAX_HEADER_MISMATCH_TRACK];
		int pos = 0;
		int show_mismatch_num = smaller_tail_count < MAX_HEADER_MISMATCH_TRACK ?
					smaller_tail_count : MAX_HEADER_MISMATCH_TRACK;
		struct json_object *jobj;

		if (json_object_object_get_ex(metadata, "objName", &jobj))
			name = json_object_get_string(jobj);
		if (json_object_object_get_ex(metadata, "mediaBankId", &jobj))
			media_bank = json_object_get_int(jobj);

		for (int i = 0; i < show_mismatch_num; i++)
			pos += snprintf(&str_mismatches[pos], STR_HEX32_SIZE + 1, "0x%08X ",
				       offset_tail_mismatches[best_offset][i]);

		SOLIDIGM_LOG_WARNING("%s:%d with %d header mismatches ( %s). Configuration file may be missing format headers.",
				      name, media_bank, smaller_tail_count, str_mismatches);
	}
	nlog_get_events(nlog, nlog_size, best_offset, formats, events, NULL);

	json_object_object_add(output, "events", events);
	return 0;
}