On Mon, Jan 11, 2016 at 9:41 AM, Peter Hutterer <peter.hutterer@xxxxxxxxx> wrote: > On Tue, Jan 05, 2016 at 03:26:41AM +0530, Aniroop Mathur wrote: >> This patch introduces concept to drop partial events in evdev handler >> itself after emptying the buffer which are dropped by all evdev >> clients in userspace after SYN_DROPPED occurs and this in turn reduces >> evdev client reading requests plus saves memory space filled by partial >> events in evdev handler buffer. >> Also, this patch prevents dropping of full packet by evdev client after >> SYN_DROPPED occurs in case last stored event was SYN_REPORT. >> (like after clock change request) > > this patch looks technically correct now, thanks. but tbh, especially after > reading the EVIOCGBUFSIZE patch I'm wondering why you need to optimise this > path. ignoring events after a SYN_DROPPED is easy in userspace, and you'll > need the code to do so anyway because even with your patch, there is no API > guarantee that this will always happen - if you rely on it, your code may > break on a future kernel. > > From userland, this patch has no real effect, it only slightly reduces the > chance that you get a SYN_DROPPED while reading events after a SYN_DROPPED > has already occured. And if that's a problem, fixing the kernel is likely > the wrong solution anyway. so yeah, still in doubt about whether this patch > provides any real benefit. > Hello Mr. Peter, I'm sorry that I'm really not able to understand you fully above. Please, provide your opinion after seeing below reason of this patch and elaborate more on above, if still required. As you can understand by seeing the patch code, this patch is required for three reasons as follows: 1. To fix bug of dropping full valid packet events by userspace clients in case last packet was fully stored and then syn_dropped occurs. For example: Consider kernel buf contains: ... SYN_REPORT REL_X, REL_Y, SYN_REPORT <one event space> Now consider case that clock type is changed, so these events will be dropped and syn_dropped will be queued. OR consider second case that new first packet event occur and that is stored in last event space left, so all stored events will be dropped and syn_dropped will be queued + newest event as per current code. So now for first case, kernel buf contains: SYN_DROPPED and for second case, kernel buf contains: SYN_DROPPED REL_X Next consider that full packet is finished storing for both cases and user-space is notified that events are ready to be read. So now kernel buf contains: SYN_DROPPED REL_X REL_Y SYN_REPORT But this new valid full packet event will be ignored by the userspace client as mentioned in documentation that userspace clients ignore all events up to and including next SYN_REPORT. As you know, this valid full event should not be ignored by the userspace. So this patch fixes this bug. 2. To save small memory filled with partial events in evdev handler kernel buffer after syn_dropped as these partial events will not be consumed by clients anyways so no need to store them as well. For example: Consider full packet as REL_X REL_Y REL_Z REL_RX REL_RY REL_RZ SYN_REPORT as in case of magnetic sensor data which includes raw data along x, y, z axis and noise data along x, y, z axis. Consider kernel buf contains: SYN_DROPPED REL_Y REL_Z REL_RX REL_RY REL_RZ SYN_REPORT REL_X REL_Y ... As you know, REL_Y REL_Z REL_RX REL_RY REL_RZ are partial events that will not be consumed by userspace clients, so this patch saves memory space of these partial events by not storing them as it not consumed by clients as well. With this patch, kernel buf will contain only required events: SYN_DROPPED SYN_REPORT REL_X REL_Y ... 3. To reduce few looping iterations of reading partial events by user space clients after syn_dropped occurs. For example: Userspace client reads some events and userspace buf contains: SYN_DROPPED REL_Y REL_Z REL_RX REL_RY REL_RZ SYN_REPORT REL_X <more events> .. Client will process syn_dropped and decides to ignore next events until syn_report occurs. So it processes REL_Y but ignores, processes REL_Z but ignores, processes REL_RX but ignores, processes REL_RY but ignores, processes REL_RZ but ignores and then it processes SYN_REPORT after which it decides to not ignore any events any more. All this processing will basically be done in a loop so with this patch extra looping cycles of partial events are removed because with this patch userspace buf will contain: SYN_DROPPED SYN_REPORT REL_X REL_Y <more events> Hence we have saved a few looping cycles here. I also think that there is a need to change the patch title and description as well to make it better: Subject: Drop partial events and queue syn_report after syn_dropped occurs. Description: This patch introduces concept to drop partial events and queue syn_report after syn_dropped which in turn does the following jobs: - Fixes bug of dropping full valid packet events by userspace clients in case last packet was fully stored and then syn_dropped occurs. - Save small memory filled with partial events in evdev handler kernel buffer after syn_dropped as these partial events will not be consumed by clients anyways so no need to store them as well. - Reduces few looping iterations of processing partial events by userspace clients after syn_dropped occurs. Thanks. BR, Aniroop Mathur > Cheers, > Peter > >> -- >> Please ignore v3. >> >> Signed-off-by: Aniroop Mathur <a.mathur@xxxxxxxxxxx> >> --- >> drivers/input/evdev.c | 53 ++++++++++++++++++++++++++++++++++++++------------- >> 1 file changed, 40 insertions(+), 13 deletions(-) >> >> diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c >> index e9ae3d5..15b6eb2 100644 >> --- a/drivers/input/evdev.c >> +++ b/drivers/input/evdev.c >> @@ -58,6 +58,7 @@ struct evdev_client { >> struct list_head node; >> unsigned int clk_type; >> bool revoked; >> + bool drop_pevent; /* specifies if partial events need to be dropped */ >> unsigned long *evmasks[EV_CNT]; >> unsigned int bufsize; >> struct input_event buffer[]; >> @@ -156,7 +157,12 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) >> static void __evdev_queue_syn_dropped(struct evdev_client *client) >> { >> struct input_event ev; >> + struct input_event *prev_ev; >> ktime_t time; >> + unsigned int mask = client->bufsize - 1; >> + >> + /* Store previous event */ >> + prev_ev = &client->buffer[(client->head - 1) & mask]; >> >> time = client->clk_type == EV_CLK_REAL ? >> ktime_get_real() : >> @@ -170,13 +176,33 @@ static void __evdev_queue_syn_dropped(struct evdev_client *client) >> ev.value = 0; >> >> client->buffer[client->head++] = ev; >> - client->head &= client->bufsize - 1; >> + client->head &= mask; >> >> if (unlikely(client->head == client->tail)) { >> /* drop queue but keep our SYN_DROPPED event */ >> - client->tail = (client->head - 1) & (client->bufsize - 1); >> + client->tail = (client->head - 1) & mask; >> client->packet_head = client->tail; >> } >> + >> + /* >> + * If last packet is NOT fully stored, set drop_pevent to true to >> + * ignore partial events and if last packet is fully stored, queue >> + * SYN_REPORT so that clients would not ignore next full packet. >> + */ >> + if (prev_ev->type != EV_SYN && prev_ev->code != SYN_REPORT) { >> + client->drop_pevent = true; >> + } else if (prev_ev->type == EV_SYN && prev_ev->code == SYN_REPORT) { >> + prev_ev->time = ev.time; >> + client->buffer[client->head++] = *prev_ev; >> + client->head &= mask; >> + client->packet_head = client->head; >> + >> + /* drop queue but keep our SYN_DROPPED & SYN_REPORT event */ >> + if (unlikely(client->head == client->tail)) { >> + client->tail = (client->head - 2) & mask; >> + client->packet_head = client->tail; >> + } >> + } >> } >> >> static void evdev_queue_syn_dropped(struct evdev_client *client) >> @@ -235,18 +261,8 @@ static void __pass_event(struct evdev_client *client, >> client->head &= client->bufsize - 1; >> >> if (unlikely(client->head == client->tail)) { >> - /* >> - * This effectively "drops" all unconsumed events, leaving >> - * EV_SYN/SYN_DROPPED plus the newest event in the queue. >> - */ >> - client->tail = (client->head - 2) & (client->bufsize - 1); >> - >> - client->buffer[client->tail].time = event->time; >> - client->buffer[client->tail].type = EV_SYN; >> - client->buffer[client->tail].code = SYN_DROPPED; >> - client->buffer[client->tail].value = 0; >> - >> client->packet_head = client->tail; >> + __evdev_queue_syn_dropped(client); >> } >> >> if (event->type == EV_SYN && event->code == SYN_REPORT) { >> @@ -284,6 +300,17 @@ static void evdev_pass_values(struct evdev_client *client, >> wakeup = true; >> } >> >> + /* >> + * drop partial events of last packet but queue SYN_REPORT >> + * so that clients would not ignore extra full packet. >> + */ >> + if (client->drop_pevent) { >> + if (v->type == EV_SYN && v->code == SYN_REPORT) >> + client->drop_pevent = false; >> + else >> + continue; >> + } >> + >> event.type = v->type; >> event.code = v->code; >> event.value = v->value; >> -- >> 2.6.2 >> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-input" in >> the body of a message to majordomo@xxxxxxxxxxxxxxx >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html