1703faabfSKonstantin Ananyev/*
2703faabfSKonstantin Ananyev * Copyright (c) 2019  Intel Corporation.
3703faabfSKonstantin Ananyev * Licensed under the Apache License, Version 2.0 (the "License");
4703faabfSKonstantin Ananyev * you may not use this file except in compliance with the License.
5703faabfSKonstantin Ananyev * You may obtain a copy of the License at:
6703faabfSKonstantin Ananyev *
7703faabfSKonstantin Ananyev *     http://www.apache.org/licenses/LICENSE-2.0
8703faabfSKonstantin Ananyev *
9703faabfSKonstantin Ananyev * Unless required by applicable law or agreed to in writing, software
10703faabfSKonstantin Ananyev * distributed under the License is distributed on an "AS IS" BASIS,
11703faabfSKonstantin Ananyev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12703faabfSKonstantin Ananyev * See the License for the specific language governing permissions and
13703faabfSKonstantin Ananyev * limitations under the License.
14703faabfSKonstantin Ananyev */
15703faabfSKonstantin Ananyev
16703faabfSKonstantin Ananyev#include "memtank.h"
17703faabfSKonstantin Ananyev#include <inttypes.h>
18703faabfSKonstantin Ananyev
19703faabfSKonstantin Ananyev#define CHUNK_OBJ_LT_NUM	4
20703faabfSKonstantin Ananyev
21703faabfSKonstantin Ananyevstruct mchunk_stat {
22703faabfSKonstantin Ananyev	uint32_t nb_empty;
23703faabfSKonstantin Ananyev	uint32_t nb_full;
24703faabfSKonstantin Ananyev	struct {
25703faabfSKonstantin Ananyev		uint32_t nb_chunk;
26703faabfSKonstantin Ananyev		uint32_t nb_obj;
27703faabfSKonstantin Ananyev		struct {
28703faabfSKonstantin Ananyev			uint32_t val;
29703faabfSKonstantin Ananyev			uint32_t num;
30703faabfSKonstantin Ananyev		} chunk_obj_lt[CHUNK_OBJ_LT_NUM];
31703faabfSKonstantin Ananyev	} used;
32703faabfSKonstantin Ananyev};
33703faabfSKonstantin Ananyev
34703faabfSKonstantin Ananyevstruct mfree_stat {
35703faabfSKonstantin Ananyev	uint32_t nb_chunk;
36703faabfSKonstantin Ananyev	struct mchunk_stat chunk;
37703faabfSKonstantin Ananyev};
38703faabfSKonstantin Ananyev
39703faabfSKonstantin Ananyev#define	MTANK_LOG(lvl, fmt, args...)	RTE_LOG(lvl, USER1, fmt, ##args)
40703faabfSKonstantin Ananyev
41703faabfSKonstantin Ananyev
42703faabfSKonstantin Ananyevstatic void
43703faabfSKonstantin Ananyevmchunk_stat_dump(FILE *f, const struct mchunk_stat *st)
44703faabfSKonstantin Ananyev{
45703faabfSKonstantin Ananyev	uint32_t i;
46703faabfSKonstantin Ananyev
47703faabfSKonstantin Ananyev	fprintf(f, "\t\tstat={\n");
48703faabfSKonstantin Ananyev	fprintf(f, "\t\t\tnb_empty=%u,\n", st->nb_empty);
49703faabfSKonstantin Ananyev	fprintf(f, "\t\t\tnb_full=%u,\n", st->nb_full);
50703faabfSKonstantin Ananyev	fprintf(f, "\t\t\tused={\n");
51703faabfSKonstantin Ananyev	fprintf(f, "\t\t\t\tnb_chunk=%u,\n", st->used.nb_chunk);
52703faabfSKonstantin Ananyev	fprintf(f, "\t\t\t\tnb_obj=%u,\n", st->used.nb_obj);
53703faabfSKonstantin Ananyev
54703faabfSKonstantin Ananyev	for (i = 0; i != RTE_DIM(st->used.chunk_obj_lt); i++) {
55703faabfSKonstantin Ananyev		if (st->used.chunk_obj_lt[i].num != 0)
56703faabfSKonstantin Ananyev			fprintf(f, "\t\t\t\tnb_chunk_obj_lt_%u=%u,\n",
57703faabfSKonstantin Ananyev				st->used.chunk_obj_lt[i].val,
58703faabfSKonstantin Ananyev				st->used.chunk_obj_lt[i].num);
59703faabfSKonstantin Ananyev	}
60703faabfSKonstantin Ananyev
61703faabfSKonstantin Ananyev	fprintf(f, "\t\t\t},\n");
62703faabfSKonstantin Ananyev	fprintf(f, "\t\t},\n");
63703faabfSKonstantin Ananyev}
64703faabfSKonstantin Ananyev
65703faabfSKonstantin Ananyevstatic void
66703faabfSKonstantin Ananyevmchunk_stat_init(struct mchunk_stat *st, uint32_t nb_obj_chunk)
67703faabfSKonstantin Ananyev{
68703faabfSKonstantin Ananyev	uint32_t i;
69703faabfSKonstantin Ananyev
70703faabfSKonstantin Ananyev	memset(st, 0, sizeof(*st));
71703faabfSKonstantin Ananyev	for (i = 0; i != RTE_DIM(st->used.chunk_obj_lt); i++) {
72703faabfSKonstantin Ananyev		st->used.chunk_obj_lt[i].val = (i + 1) * nb_obj_chunk /
73703faabfSKonstantin Ananyev			RTE_DIM(st->used.chunk_obj_lt);
74703faabfSKonstantin Ananyev	}
75703faabfSKonstantin Ananyev}
76703faabfSKonstantin Ananyev
77703faabfSKonstantin Ananyevstatic void
78703faabfSKonstantin Ananyevmchunk_stat_collect(struct mchunk_stat *st, const struct memchunk *ch)
79703faabfSKonstantin Ananyev{
80703faabfSKonstantin Ananyev	uint32_t i, n;
81703faabfSKonstantin Ananyev
82703faabfSKonstantin Ananyev	n = ch->nb_total - ch->nb_free;
83703faabfSKonstantin Ananyev
84703faabfSKonstantin Ananyev	if (ch->nb_free == 0)
85703faabfSKonstantin Ananyev		st->nb_empty++;
86703faabfSKonstantin Ananyev	else if (n == 0)
87703faabfSKonstantin Ananyev		st->nb_full++;
88703faabfSKonstantin Ananyev	else {
89703faabfSKonstantin Ananyev		st->used.nb_chunk++;
90703faabfSKonstantin Ananyev		st->used.nb_obj += n;
91703faabfSKonstantin Ananyev
92703faabfSKonstantin Ananyev		for (i = 0; i != RTE_DIM(st->used.chunk_obj_lt); i++) {
93703faabfSKonstantin Ananyev			if (n < st->used.chunk_obj_lt[i].val) {
94703faabfSKonstantin Ananyev				st->used.chunk_obj_lt[i].num++;
95703faabfSKonstantin Ananyev				break;
96703faabfSKonstantin Ananyev			}
97703faabfSKonstantin Ananyev		}
98703faabfSKonstantin Ananyev	}
99703faabfSKonstantin Ananyev}
100703faabfSKonstantin Ananyev
101703faabfSKonstantin Ananyevstatic void
102703faabfSKonstantin Ananyevmchunk_list_dump(FILE *f, struct memtank *mt, uint32_t idx, uint32_t flags)
103703faabfSKonstantin Ananyev{
104703faabfSKonstantin Ananyev	struct mchunk_list *ls;
105703faabfSKonstantin Ananyev	const struct memchunk *ch;
106703faabfSKonstantin Ananyev	struct mchunk_stat mcs;
107703faabfSKonstantin Ananyev
108703faabfSKonstantin Ananyev	ls = &mt->chl[idx];
109703faabfSKonstantin Ananyev	mchunk_stat_init(&mcs, mt->prm.nb_obj_chunk);
110703faabfSKonstantin Ananyev
111703faabfSKonstantin Ananyev	rte_spinlock_lock(&ls->lock);
112703faabfSKonstantin Ananyev
113703faabfSKonstantin Ananyev	for (ch = TAILQ_FIRST(&ls->chunk); ch != NULL;
114703faabfSKonstantin Ananyev			ch = TAILQ_NEXT(ch, link)) {
115703faabfSKonstantin Ananyev
116703faabfSKonstantin Ananyev		/* collect chunk stats */
117703faabfSKonstantin Ananyev		if (flags & TLE_MTANK_DUMP_CHUNK_STAT)
118703faabfSKonstantin Ananyev			mchunk_stat_collect(&mcs, ch);
119703faabfSKonstantin Ananyev
120703faabfSKonstantin Ananyev		/* dump chunk metadata */
121703faabfSKonstantin Ananyev		if (flags & TLE_MTANK_DUMP_CHUNK) {
122703faabfSKonstantin Ananyev			fprintf(f, "\t\tmemchunk@%p={\n", ch);
123703faabfSKonstantin Ananyev			fprintf(f, "\t\t\traw=%p,\n", ch->raw);
124703faabfSKonstantin Ananyev			fprintf(f, "\t\t\tnb_total=%u,\n", ch->nb_total);
125703faabfSKonstantin Ananyev			fprintf(f, "\t\t\tnb_free=%u,\n", ch->nb_free);
126703faabfSKonstantin Ananyev			fprintf(f, "\t\t},\n");
127703faabfSKonstantin Ananyev		}
128703faabfSKonstantin Ananyev	}
129703faabfSKonstantin Ananyev
130703faabfSKonstantin Ananyev	rte_spinlock_unlock(&ls->lock);
131703faabfSKonstantin Ananyev
132703faabfSKonstantin Ananyev	/* print chunk stats */
133703faabfSKonstantin Ananyev	if (flags & TLE_MTANK_DUMP_CHUNK_STAT)
134703faabfSKonstantin Ananyev		mchunk_stat_dump(f, &mcs);
135703faabfSKonstantin Ananyev}
136703faabfSKonstantin Ananyev
137703faabfSKonstantin Ananyevstatic void
138703faabfSKonstantin Ananyevmfree_stat_init(struct mfree_stat *st, uint32_t nb_obj_chunk)
139703faabfSKonstantin Ananyev{
140703faabfSKonstantin Ananyev	st->nb_chunk = 0;
141703faabfSKonstantin Ananyev	mchunk_stat_init(&st->chunk, nb_obj_chunk);
142703faabfSKonstantin Ananyev}
143703faabfSKonstantin Ananyev
144703faabfSKonstantin Ananyevstatic int
145703faabfSKonstantin Ananyevptr_cmp(const void *p1, const void *p2)
146703faabfSKonstantin Ananyev{
147703faabfSKonstantin Ananyev	const intptr_t *v1, *v2;
148703faabfSKonstantin Ananyev
149703faabfSKonstantin Ananyev	v1 = p1;
150703faabfSKonstantin Ananyev	v2 = p2;
151703faabfSKonstantin Ananyev	return v1[0] - v2[0];
152703faabfSKonstantin Ananyev}
153703faabfSKonstantin Ananyev
154703faabfSKonstantin Ananyevstatic void
155703faabfSKonstantin Ananyevmfree_stat_collect(struct mfree_stat *st, struct memtank *mt)
156703faabfSKonstantin Ananyev{
157703faabfSKonstantin Ananyev	uint32_t i, j, n, sz;
158703faabfSKonstantin Ananyev	uintptr_t *p;
159703faabfSKonstantin Ananyev	const struct memobj *mo;
160703faabfSKonstantin Ananyev
161703faabfSKonstantin Ananyev	sz = mt->obj_size;
162703faabfSKonstantin Ananyev
163703faabfSKonstantin Ananyev	p = malloc(mt->pub.max_free * sizeof(*p));
164703faabfSKonstantin Ananyev	if (p == NULL)
165703faabfSKonstantin Ananyev		return;
166703faabfSKonstantin Ananyev
167703faabfSKonstantin Ananyev	/**
168703faabfSKonstantin Ananyev	 * grab free lock and keep it till we analyze related memchunks,
169703faabfSKonstantin Ananyev	 * to make sure none of these memchunks will be freed untill
170703faabfSKonstantin Ananyev	 * we are finished.
171703faabfSKonstantin Ananyev	 */
172703faabfSKonstantin Ananyev	rte_spinlock_lock(&mt->pub.lock);
173703faabfSKonstantin Ananyev
174703faabfSKonstantin Ananyev	/* collect chunks for all objects in free[] */
175703faabfSKonstantin Ananyev	n = mt->pub.nb_free;
176703faabfSKonstantin Ananyev	memcpy(p, mt->pub.free, n * sizeof(*p));
177703faabfSKonstantin Ananyev	for (i = 0; i != n; i++) {
178703faabfSKonstantin Ananyev		mo = obj_pub_full(p[i], sz);
179703faabfSKonstantin Ananyev		p[i] = (uintptr_t)mo->chunk;
180703faabfSKonstantin Ananyev	}
181703faabfSKonstantin Ananyev
182703faabfSKonstantin Ananyev	/* sort chunk pointers */
183703faabfSKonstantin Ananyev	qsort(p, n, sizeof(*p), ptr_cmp);
184703faabfSKonstantin Ananyev
185703faabfSKonstantin Ananyev	/* for each chunk collect stats */
186703faabfSKonstantin Ananyev	for (i = 0; i != n; i = j) {
187703faabfSKonstantin Ananyev
188703faabfSKonstantin Ananyev		st->nb_chunk++;
189703faabfSKonstantin Ananyev		mchunk_stat_collect(&st->chunk, (const struct memchunk *)p[i]);
190703faabfSKonstantin Ananyev		for (j = i + 1; j != n && p[i] == p[j]; j++)
191703faabfSKonstantin Ananyev			;
192703faabfSKonstantin Ananyev	}
193703faabfSKonstantin Ananyev
194703faabfSKonstantin Ananyev	rte_spinlock_unlock(&mt->pub.lock);
195703faabfSKonstantin Ananyev	free(p);
196703faabfSKonstantin Ananyev}
197703faabfSKonstantin Ananyev
198703faabfSKonstantin Ananyevstatic void
199703faabfSKonstantin Ananyevmfree_stat_dump(FILE *f, const struct mfree_stat *st)
200703faabfSKonstantin Ananyev{
201703faabfSKonstantin Ananyev	fprintf(f, "\tfree_stat={\n");
202703faabfSKonstantin Ananyev	fprintf(f, "\t\tnb_chunk=%u,\n", st->nb_chunk);
203703faabfSKonstantin Ananyev	mchunk_stat_dump(f, &st->chunk);
204703faabfSKonstantin Ananyev	fprintf(f, "\t},\n");
205703faabfSKonstantin Ananyev}
206703faabfSKonstantin Ananyev
207703faabfSKonstantin Ananyevvoid
208703faabfSKonstantin Ananyevtle_memtank_dump(FILE *f, const struct tle_memtank *t, uint32_t flags)
209703faabfSKonstantin Ananyev{
210703faabfSKonstantin Ananyev	struct memtank *mt;
211703faabfSKonstantin Ananyev
212703faabfSKonstantin Ananyev	if (f == NULL || t == NULL)
213703faabfSKonstantin Ananyev		return;
214703faabfSKonstantin Ananyev
215703faabfSKonstantin Ananyev	mt = tank_pub_full(t);
216703faabfSKonstantin Ananyev
217703faabfSKonstantin Ananyev	fprintf(f, "tle_memtank@%p={\n", t);
218703faabfSKonstantin Ananyev	fprintf(f, "\tmin_free=%u,\n", t->min_free);
219703faabfSKonstantin Ananyev	fprintf(f, "\tmax_free=%u,\n", t->max_free);
220703faabfSKonstantin Ananyev	fprintf(f, "\tnb_free=%u,\n", t->nb_free);
221703faabfSKonstantin Ananyev	fprintf(f, "\tchunk_size=%zu,\n", mt->chunk_size);
222703faabfSKonstantin Ananyev	fprintf(f, "\tobj_size=%u,\n", mt->obj_size);
223703faabfSKonstantin Ananyev	fprintf(f, "\tmax_chunk=%u,\n", mt->max_chunk);
224703faabfSKonstantin Ananyev	fprintf(f, "\tflags=%#x,\n", mt->flags);
225703faabfSKonstantin Ananyev	fprintf(f, "\tnb_chunks=%u,\n", rte_atomic32_read(&mt->nb_chunks));
226703faabfSKonstantin Ananyev
227703faabfSKonstantin Ananyev	if (flags & TLE_MTANK_DUMP_FREE_STAT) {
228