Commit 15325b4f authored by Yury Norov's avatar Yury Norov
Browse files

vsprintf: rework bitmap_list_string



bitmap_list_string() is very ineffective when printing bitmaps with long
ranges of set bits because it calls find_next_bit for each bit in the
bitmap.  We can do better by detecting ranges of set bits.

In my environment, before/after is 943008/31008 ns.

Signed-off-by: default avatarYury Norov <yury.norov@gmail.com>
Tested-by: default avatarWolfram Sang <wsa+renesas@sang-engineering.com>
parent db731300
Loading
Loading
Loading
Loading
+7 −17
Original line number Diff line number Diff line
@@ -1241,20 +1241,13 @@ char *bitmap_list_string(char *buf, char *end, unsigned long *bitmap,
			 struct printf_spec spec, const char *fmt)
{
	int nr_bits = max_t(int, spec.field_width, 0);
	/* current bit is 'cur', most recently seen range is [rbot, rtop] */
	int cur, rbot, rtop;
	bool first = true;
	int rbot, rtop;

	if (check_pointer(&buf, end, bitmap, spec))
		return buf;

	rbot = cur = find_first_bit(bitmap, nr_bits);
	while (cur < nr_bits) {
		rtop = cur;
		cur = find_next_bit(bitmap, nr_bits, cur + 1);
		if (cur < nr_bits && cur <= rtop + 1)
			continue;

	for_each_set_bitrange(rbot, rtop, bitmap, nr_bits) {
		if (!first) {
			if (buf < end)
				*buf = ',';
@@ -1263,15 +1256,12 @@ char *bitmap_list_string(char *buf, char *end, unsigned long *bitmap,
		first = false;

		buf = number(buf, end, rbot, default_dec_spec);
		if (rbot < rtop) {
		if (rtop == rbot + 1)
			continue;

		if (buf < end)
			*buf = '-';
			buf++;

			buf = number(buf, end, rtop, default_dec_spec);
		}

		rbot = cur;
		buf = number(++buf, end, rtop - 1, default_dec_spec);
	}
	return buf;
}