Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 266ea6b0 authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

Merge "Optimize EventHub to process events in big chunks. (DO NOT MERGE)" into honeycomb-mr2

parents 85a7f99c dbf8d27f
Loading
Loading
Loading
Loading
+97 −84
Original line number Diff line number Diff line
@@ -127,9 +127,11 @@ EventHub::EventHub(void) :
        mError(NO_INIT), mBuiltInKeyboardId(-1), mNextDeviceId(1),
        mOpeningDevices(0), mClosingDevices(0),
        mOpened(false), mNeedToSendFinishedDeviceScan(false),
        mInputBufferIndex(0), mInputBufferCount(0), mInputFdIndex(0) {
        mInputFdIndex(1) {
    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

    memset(mSwitches, 0, sizeof(mSwitches));
    mNumCpus = sysconf(_SC_NPROCESSORS_ONLN);
}

EventHub::~EventHub(void) {
@@ -445,17 +447,10 @@ EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
    return NULL;
}

bool EventHub::getEvent(int timeoutMillis, RawEvent* outEvent) {
    outEvent->deviceId = 0;
    outEvent->type = 0;
    outEvent->scanCode = 0;
    outEvent->keyCode = 0;
    outEvent->flags = 0;
    outEvent->value = 0;
    outEvent->when = 0;

    // Note that we only allow one caller to getEvent(), so don't need
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    // Note that we only allow one caller to getEvents(), so don't need
    // to do locking here...  only when adding/removing devices.
    assert(bufferSize >= 1);

    if (!mOpened) {
        mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
@@ -463,99 +458,62 @@ bool EventHub::getEvent(int timeoutMillis, RawEvent* outEvent) {
        mNeedToSendFinishedDeviceScan = true;
    }

    struct input_event readBuffer[bufferSize];

    RawEvent* event = buffer;
    size_t capacity = bufferSize;
    for (;;) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

        // Report any devices that had last been added/removed.
        if (mClosingDevices != NULL) {
        while (mClosingDevices) {
            Device* device = mClosingDevices;
            LOGV("Reporting device closed: id=%d, name=%s\n",
                 device->id, device->path.string());
            mClosingDevices = device->next;
            if (device->id == mBuiltInKeyboardId) {
                outEvent->deviceId = 0;
            } else {
                outEvent->deviceId = device->id;
            }
            outEvent->type = DEVICE_REMOVED;
            outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            event->type = DEVICE_REMOVED;
            event += 1;
            delete device;
            mNeedToSendFinishedDeviceScan = true;
            return true;
            if (--capacity == 0) {
                break;
            }
        }

        if (mOpeningDevices != NULL) {
        while (mOpeningDevices != NULL) {
            Device* device = mOpeningDevices;
            LOGV("Reporting device opened: id=%d, name=%s\n",
                 device->id, device->path.string());
            mOpeningDevices = device->next;
            if (device->id == mBuiltInKeyboardId) {
                outEvent->deviceId = 0;
            } else {
                outEvent->deviceId = device->id;
            }
            outEvent->type = DEVICE_ADDED;
            outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            event->type = DEVICE_ADDED;
            event += 1;
            mNeedToSendFinishedDeviceScan = true;
            return true;
            if (--capacity == 0) {
                break;
            }
        }

        if (mNeedToSendFinishedDeviceScan) {
            mNeedToSendFinishedDeviceScan = false;
            outEvent->type = FINISHED_DEVICE_SCAN;
            outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
            return true;
            event->when = now;
            event->type = FINISHED_DEVICE_SCAN;
            event += 1;
            if (--capacity == 0) {
                break;
            }
        }

        // Grab the next input event.
        // mInputFdIndex is initially 1 because index 0 is used for inotify.
        bool deviceWasRemoved = false;
        for (;;) {
            // Consume buffered input events, if any.
            if (mInputBufferIndex < mInputBufferCount) {
                const struct input_event& iev = mInputBufferData[mInputBufferIndex++];
                const Device* device = mDevices[mInputFdIndex];

                LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(),
                     (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value);
                if (device->id == mBuiltInKeyboardId) {
                    outEvent->deviceId = 0;
                } else {
                    outEvent->deviceId = device->id;
                }
                outEvent->type = iev.type;
                outEvent->scanCode = iev.code;
                outEvent->flags = 0;
                if (iev.type == EV_KEY) {
                    outEvent->keyCode = AKEYCODE_UNKNOWN;
                    if (device->keyMap.haveKeyLayout()) {
                        status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code,
                                &outEvent->keyCode, &outEvent->flags);
                        LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
                                iev.code, outEvent->keyCode, outEvent->flags, err);
                    }
                } else {
                    outEvent->keyCode = iev.code;
                }
                outEvent->value = iev.value;

                // Use an event timestamp in the same timebase as
                // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
                // as expected by the rest of the system.
                outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
                return true;
            }

            // Finish reading all events from devices identified in previous poll().
            // This code assumes that mInputDeviceIndex is initially 0 and that the
            // revents member of pollfd is initialized to 0 when the device is first added.
            // Since mFds[0] is used for inotify, we process regular events starting at index 1.
            mInputFdIndex += 1;
            if (mInputFdIndex >= mFds.size()) {
                break;
            }

        while (mInputFdIndex < mFds.size()) {
            const struct pollfd& pfd = mFds[mInputFdIndex];
            if (pfd.revents & POLLIN) {
                int32_t readSize = read(pfd.fd, mInputBufferData,
                        sizeof(struct input_event) * INPUT_BUFFER_SIZE);
                int32_t readSize = read(pfd.fd, readBuffer, sizeof(struct input_event) * capacity);
                if (readSize < 0) {
                    if (errno == ENODEV) {
                        deviceWasRemoved = true;
@@ -566,12 +524,44 @@ bool EventHub::getEvent(int timeoutMillis, RawEvent* outEvent) {
                    }
                } else if ((readSize % sizeof(struct input_event)) != 0) {
                    LOGE("could not get event (wrong size: %d)", readSize);
                } else if (readSize == 0) { // eof
                    deviceWasRemoved = true;
                    break;
                } else {
                    mInputBufferCount = size_t(readSize) / sizeof(struct input_event);
                    mInputBufferIndex = 0;
                    const Device* device = mDevices[mInputFdIndex];
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;

                    size_t count = size_t(readSize) / sizeof(struct input_event);
                    for (size_t i = 0; i < count; i++) {
                        const struct input_event& iev = readBuffer[i];
                        LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d",
                                device->path.string(),
                                (int) iev.time.tv_sec, (int) iev.time.tv_usec,
                                iev.type, iev.code, iev.value);

                        event->when = now;
                        event->deviceId = deviceId;
                        event->type = iev.type;
                        event->scanCode = iev.code;
                        event->value = iev.value;
                        event->keyCode = AKEYCODE_UNKNOWN;
                        event->flags = 0;
                        if (iev.type == EV_KEY && device->keyMap.haveKeyLayout()) {
                            status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code,
                                        &event->keyCode, &event->flags);
                            LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
                                    iev.code, event->keyCode, event->flags, err);
                        }
                        event += 1;
                    }
                    capacity -= count;
                    if (capacity == 0) {
                        break;
                    }
                }
            }
            mInputFdIndex += 1;
        }

        // Handle the case where a device has been removed but INotify has not yet noticed.
        if (deviceWasRemoved) {
@@ -586,10 +576,16 @@ bool EventHub::getEvent(int timeoutMillis, RawEvent* outEvent) {
        if(mFds[0].revents & POLLIN) {
            readNotify(mFds[0].fd);
            mFds.editItemAt(0).revents = 0;
            mInputFdIndex = mFds.size();
            continue; // report added or removed devices immediately
        }
#endif

        // Return now if we have collected any events, otherwise poll.
        if (event != buffer) {
            break;
        }

        // Poll for events.  Mind the wake lock dance!
        // We hold a wake lock at all times except during poll().  This works due to some
        // subtle choreography.  When a device driver has pending (unread) events, it acquires
@@ -608,19 +604,36 @@ bool EventHub::getEvent(int timeoutMillis, RawEvent* outEvent) {
        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

        if (pollResult == 0) {
            // Timed out.
            return false;
            break; // timed out
        }
        if (pollResult < 0) {
            // Sleep after errors to avoid locking up the system.
            // Hopefully the error is transient.
            if (errno != EINTR) {
                LOGW("poll failed (errno=%d)\n", errno);
                usleep(100000);
            }
        } else {
            // On an SMP system, it is possible for the framework to read input events
            // faster than the kernel input device driver can produce a complete packet.
            // Because poll() wakes up as soon as the first input event becomes available,
            // the framework will often end up reading one event at a time until the
            // packet is complete.  Instead of one call to read() returning 71 events,
            // it could take 71 calls to read() each returning 1 event.
            //
            // Sleep for a short period of time after waking up from the poll() to give
            // the kernel time to finish writing the entire packet of input events.
            if (mNumCpus > 1) {
                usleep(250);
            }
        }

        // Prepare to process all of the FDs we just polled.
        mInputFdIndex = 0;
        mInputFdIndex = 1;
    }

    // All done, return the number of events we read.
    return event - buffer;
}

/*
+10 −8
Original line number Diff line number Diff line
@@ -157,6 +157,8 @@ public:
        // Sent when all added/removed devices from the most recent scan have been reported.
        // This event is always sent at least once.
        FINISHED_DEVICE_SCAN = 0x30000000,

        FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
    };

    virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0;
@@ -181,7 +183,7 @@ public:
    virtual void addExcludedDevice(const char* deviceName) = 0;

    /*
     * Wait for the next event to become available and return it.
     * Wait for events to become available and returns them.
     * After returning, the EventHub holds onto a wake lock until the next call to getEvent.
     * This ensures that the device will not go to sleep while the event is being processed.
     * If the device needs to remain awake longer than that, then the caller is responsible
@@ -190,9 +192,9 @@ public:
     * The timeout is advisory only.  If the device is asleep, it will not wake just to
     * service the timeout.
     *
     * Returns true if an event was obtained, false if the timeout expired.
     * Returns the number of events obtained, or 0 if the timeout expired.
     */
    virtual bool getEvent(int timeoutMillis, RawEvent* outEvent) = 0;
    virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0;

    /*
     * Query current input state.
@@ -249,7 +251,7 @@ public:
    virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
            const int32_t* keyCodes, uint8_t* outFlags) const;

    virtual bool getEvent(int timeoutMillis, RawEvent* outEvent);
    virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize);

    virtual bool hasLed(int32_t deviceId, int32_t led) const;
    virtual void setLedState(int32_t deviceId, int32_t led, bool on);
@@ -336,11 +338,11 @@ private:
    // device ids that report particular switches.
    int32_t mSwitches[SW_MAX + 1];

    static const int INPUT_BUFFER_SIZE = 64;
    struct input_event mInputBufferData[INPUT_BUFFER_SIZE];
    size_t mInputBufferIndex;
    size_t mInputBufferCount;
    // The index of the next file descriptor that needs to be read.
    size_t mInputFdIndex;

    // Set to the number of CPUs.
    int32_t mNumCpus;
};

}; // namespace android
+61 −34
Original line number Diff line number Diff line
@@ -250,15 +250,11 @@ void InputReader::loopOnce() {
        timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
    }

    RawEvent rawEvent;
    if (mEventHub->getEvent(timeoutMillis, &rawEvent)) {
#if DEBUG_RAW_EVENTS
        LOGD("Input event: device=%d type=0x%04x scancode=0x%04x keycode=0x%04x value=0x%04x",
                rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode,
                rawEvent.value);
#endif
        process(&rawEvent);
    } else {
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
    if (count) {
        processEvents(mEventBuffer, count);
    }
    if (!count || timeoutMillis == 0) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
#if DEBUG_RAW_EVENTS
        LOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
@@ -268,25 +264,43 @@ void InputReader::loopOnce() {
    }
}

void InputReader::process(const RawEvent* rawEvent) {
void InputReader::processEvents(const RawEvent* rawEvents, size_t count) {
    for (const RawEvent* rawEvent = rawEvents; count;) {
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
            int32_t deviceId = rawEvent->deviceId;
            while (batchSize < count) {
                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
                        || rawEvent[batchSize].deviceId != deviceId) {
                    break;
                }
                batchSize += 1;
            }
#if DEBUG_RAW_EVENTS
            LOGD("BatchSize: %d Count: %d", batchSize, count);
#endif
            processEventsForDevice(deviceId, rawEvent, batchSize);
        } else {
            switch (rawEvent->type) {
            case EventHubInterface::DEVICE_ADDED:
                addDevice(rawEvent->deviceId);
                break;

            case EventHubInterface::DEVICE_REMOVED:
                removeDevice(rawEvent->deviceId);
                break;

            case EventHubInterface::FINISHED_DEVICE_SCAN:
                handleConfigurationChanged(rawEvent->when);
                break;

            default:
        consumeEvent(rawEvent);
                assert(false); // can't happen
                break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

void InputReader::addDevice(int32_t deviceId) {
    String8 name = mEventHub->getDeviceName(deviceId);
@@ -405,9 +419,8 @@ InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, ui
    return device;
}

void InputReader::consumeEvent(const RawEvent* rawEvent) {
    int32_t deviceId = rawEvent->deviceId;

void InputReader::processEventsForDevice(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
    { // acquire device registry reader lock
        RWLock::AutoRLock _rl(mDeviceRegistryLock);

@@ -423,7 +436,7 @@ void InputReader::consumeEvent(const RawEvent* rawEvent) {
            return;
        }

        device->process(rawEvent);
        device->process(rawEvents, count);
    } // release device registry reader lock
}

@@ -785,13 +798,27 @@ void InputDevice::reset() {
    }
}

void InputDevice::process(const RawEvent* rawEvent) {
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    // Process all of the events in order for each mapper.
    // We cannot simply ask each mapper to process them in bulk because mappers may
    // have side-effects that must be interleaved.  For example, joystick movement events and
    // gamepad button presses are handled by different mappers but they should be dispatched
    // in the order received.
    size_t numMappers = mMappers.size();
    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
#if DEBUG_RAW_EVENTS
        LOGD("Input event: device=%d type=0x%04x scancode=0x%04x "
                "keycode=0x%04x value=0x%04x flags=0x%08x",
                rawEvent->deviceId, rawEvent->type, rawEvent->scanCode, rawEvent->keyCode,
                rawEvent->value, rawEvent->flags);
#endif

        for (size_t i = 0; i < numMappers; i++) {
            InputMapper* mapper = mMappers[i];
            mapper->process(rawEvent);
        }
    }
}

void InputDevice::timeoutExpired(nsecs_t when) {
    size_t numMappers = mMappers.size();
+10 −7
Original line number Diff line number Diff line
@@ -216,6 +216,10 @@ private:
    virtual InputDispatcherInterface* getDispatcher() { return mDispatcher.get(); }
    virtual EventHubInterface* getEventHub() { return mEventHub.get(); }

    // The event queue.
    static const int EVENT_BUFFER_SIZE = 256;
    RawEvent mEventBuffer[EVENT_BUFFER_SIZE];

    // This reader/writer lock guards the list of input devices.
    // The writer lock must be held whenever the list of input devices is modified
    //   and then promptly released.
@@ -228,16 +232,15 @@ private:
    KeyedVector<int32_t, InputDevice*> mDevices;

    // low-level input event decoding and device management
    void process(const RawEvent* rawEvent);
    void processEvents(const RawEvent* rawEvents, size_t count);

    void addDevice(int32_t deviceId);
    void removeDevice(int32_t deviceId);
    void configureExcludedDevices();

    void consumeEvent(const RawEvent* rawEvent);
    void processEventsForDevice(int32_t deviceId, const RawEvent* rawEvents, size_t count);
    void timeoutExpired(nsecs_t when);

    void handleConfigurationChanged(nsecs_t when);
    void configureExcludedDevices();

    // state management for all devices
    Mutex mStateLock;
@@ -251,12 +254,12 @@ private:
    InputConfiguration mInputConfiguration;
    void updateInputConfiguration();

    nsecs_t mDisableVirtualKeysTimeout;
    nsecs_t mDisableVirtualKeysTimeout; // only accessed by reader thread
    virtual void disableVirtualKeysUntil(nsecs_t time);
    virtual bool shouldDropVirtualKey(nsecs_t now,
            InputDevice* device, int32_t keyCode, int32_t scanCode);

    nsecs_t mNextTimeout;
    nsecs_t mNextTimeout; // only accessed by reader thread
    virtual void requestTimeoutAtTime(nsecs_t when);

    // state queries
@@ -301,7 +304,7 @@ public:
    void addMapper(InputMapper* mapper);
    void configure();
    void reset();
    void process(const RawEvent* rawEvent);
    void process(const RawEvent* rawEvents, size_t count);
    void timeoutExpired(nsecs_t when);

    void getDeviceInfo(InputDeviceInfo* outDeviceInfo);
+5 −5
Original line number Diff line number Diff line
@@ -622,14 +622,14 @@ private:
        mExcludedDevices.add(String8(deviceName));
    }

    virtual bool getEvent(int timeoutMillis, RawEvent* outEvent) {
    virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
        if (mEvents.empty()) {
            return false;
            return 0;
        }

        *outEvent = *mEvents.begin();
        *buffer = *mEvents.begin();
        mEvents.erase(mEvents.begin());
        return true;
        return 1;
    }

    virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const {
@@ -1445,7 +1445,7 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe

    // Event handling.
    RawEvent event;
    mDevice->process(&event);
    mDevice->process(&event, 1);

    ASSERT_NO_FATAL_FAILURE(mapper1->assertProcessWasCalled());
    ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled());