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

Commit 8ea6e641 authored by Jeff Brown's avatar Jeff Brown Committed by Android Git Automerger
Browse files

am 266ea6b0: Merge "Optimize EventHub to process events in big chunks. (DO NOT...

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

* commit '266ea6b0':
  Optimize EventHub to process events in big chunks. (DO NOT MERGE)
parents af685f3b 266ea6b0
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());