Re: [PATCH 4/9] platform/surface: aggregator: Add trace points

From: Maximilian Luz
Date: Tue Nov 17 2020 - 12:42:28 EST


On 11/17/20 5:44 PM, Steven Rostedt wrote:
On Sun, 15 Nov 2020 20:21:38 +0100
Maximilian Luz <luzmaximilian@xxxxxxxxx> wrote:

[...]

/*
* Lock packet and commit with memory barrier. If this packet has
* already been locked, it's going to be removed and completed by
@@ -1154,6 +1167,8 @@ static void ssh_ptl_timeout_reap(struct work_struct *work)
ktime_t next = KTIME_MAX;
bool resub = false;
+ trace_ssam_ptl_timeout_reap("pending", atomic_read(&ptl->pending.count));

I noticed that the only two places that use timeout_reap, both have
"pending" as a string. Is this necessary to save? Would an enum work?

I think its probably cleaner to declare an event class for those.
Currently they are using the GENERIC_UINT_EVENT class, which I intended
as mapping with string to uint, but I'm only using that in three places,
two of which are for the timeout. So dropping the GENERIC_UINT_EVENT
class is probably the best solution(?).

[...]

+/**
+ * ssam_trace_ptr_uid() - Convert the pointer to a non-pointer UID string.
+ * @ptr: The pointer to convert.
+ * @uid_str: A buffer of length SSAM_PTR_UID_LEN where the UID will be stored.
+ *
+ * Converts the given pointer into a UID string that is safe to be shared
+ * with userspace and logs, i.e. doesn't give away the real memory location.
+ */
+static inline void ssam_trace_ptr_uid(const void *ptr, char *uid_str)
+{
+ char buf[2 * sizeof(void *) + 1];
+
+ snprintf(buf, ARRAY_SIZE(buf), "%p", ptr);
+ memcpy(uid_str, &buf[ARRAY_SIZE(buf) - SSAM_PTR_UID_LEN],
+ SSAM_PTR_UID_LEN);

Is the above snprintf() to have the ptr turn into a hash?

Otherwise, couldn't you just truncate the value of ptr?

Yes, the idea is to generate the same output for a pointer as a normal
printk message would generate, i.e. generate a (truncated) hash of the
pointer. While the trace points should be enough on their own, I prefer
to have the output lining up with the kernel log, so that we can match
packets across both if ever necessary.

In any case, you want to make sure that ARRAY_SIZE(buf) is always bigger
than, or equal to, SSAM_PTR_UID_LEN, and you should probably stick a:

BUILD_BUG_ON(ARRAY_SIZE(buf) < SSAM_PTR_UID_LEN);

in there, which would cause the build to fail if that was ever the case.

Thanks! That is a good idea.

[...]

+#define ssam_trace_get_command_field_u8(packet, field) \
+ ((!packet || packet->data.len < SSH_COMMAND_MESSAGE_LENGTH(0)) \
+ ? 0 : p->data.ptr[SSH_MSGOFFSET_COMMAND(field)])

I think you want the above to be:

? 0 : packet->data.ptr[SSH_MSGOFFSET_COMMAND(field)])

The only reason it worked, is because the caller passed in "p".

Oh, right!

+DECLARE_EVENT_CLASS(ssam_packet_class,
+ TP_PROTO(const struct ssh_packet *packet),
+
+ TP_ARGS(packet),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, state)
+ __array(char, uid, SSAM_PTR_UID_LEN)
+ __field(u8, priority)
+ __field(u16, length)
+ __field(u16, seq)
+ ),
+
+ TP_fast_assign(
+ __entry->state = READ_ONCE(packet->state);
+ ssam_trace_ptr_uid(packet, __entry->uid);
+ __entry->priority = READ_ONCE(packet->priority);

I'm curious about the need for the read once here.

I generally prefer to be explicit when accessing values that can be
changed concurrently by other parties. In the very least, this should
guarantee that the value will be read as a whole in one instruction and
the compiler does not do anything unexpected (like reading it in
multiple instructions, which could lead to invalid state or priority
values).

Arguably, the latter will very likely never happen even without the
READ_ONCE, but I prefer to be on the safe side.

The rest seems fine.

Thanks,
Max