mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
![Ben Konyi](/assets/img/avatar_default.png)
prevent repeated port allocations Flutter makes heavy use of short-lived Timers which currently causes repeated opening/closing of the Timer port. This change allows for RawReceivePorts to be set active / inactive, allowing for a port to be kept open but not considered alive. Flutter benchmark changes: Before dart-lang/sdk@d5118d5: "notifyListener2_iteration": 545.0 After dart-lang/sdk@d5118d5: "notifyListener2_iteration": 1639.0 With fix: "notifyListener2_iteration": 629.0 Fixes https://github.com/flutter/flutter/issues/69583 TEST=Updated port state tests and verified change against Flutter's microbenchmarks Change-Id: I50ff1a1b0f1f29bcdac958e41c66429e9586fba2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/171628 Commit-Queue: Ben Konyi <bkonyi@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com>
191 lines
5.6 KiB
C++
191 lines
5.6 KiB
C++
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "vm/port.h"
|
|
#include "platform/assert.h"
|
|
#include "vm/lockers.h"
|
|
#include "vm/message_handler.h"
|
|
#include "vm/os.h"
|
|
#include "vm/unit_test.h"
|
|
|
|
namespace dart {
|
|
|
|
// Provides private access to PortMap for testing.
|
|
class PortMapTestPeer {
|
|
public:
|
|
static bool IsActivePort(Dart_Port port) {
|
|
MutexLocker ml(PortMap::mutex_);
|
|
auto it = PortMap::ports_->TryLookup(port);
|
|
return it != PortMap::ports_->end();
|
|
}
|
|
|
|
static bool IsLivePort(Dart_Port port) {
|
|
MutexLocker ml(PortMap::mutex_);
|
|
auto it = PortMap::ports_->TryLookup(port);
|
|
if (it == PortMap::ports_->end()) {
|
|
return false;
|
|
}
|
|
return (*it).state == PortMap::kLivePort;
|
|
}
|
|
};
|
|
|
|
class PortTestMessageHandler : public MessageHandler {
|
|
public:
|
|
PortTestMessageHandler() : notify_count(0) {}
|
|
|
|
void MessageNotify(Message::Priority priority) { notify_count++; }
|
|
|
|
MessageStatus HandleMessage(std::unique_ptr<Message> message) { return kOK; }
|
|
|
|
int notify_count;
|
|
};
|
|
|
|
TEST_CASE(PortMap_CreateAndCloseOnePort) {
|
|
PortTestMessageHandler handler;
|
|
Dart_Port port = PortMap::CreatePort(&handler);
|
|
EXPECT_NE(0, port);
|
|
EXPECT(PortMapTestPeer::IsActivePort(port));
|
|
|
|
PortMap::ClosePort(port);
|
|
EXPECT(!PortMapTestPeer::IsActivePort(port));
|
|
}
|
|
|
|
TEST_CASE(PortMap_CreateAndCloseTwoPorts) {
|
|
PortTestMessageHandler handler;
|
|
Dart_Port port1 = PortMap::CreatePort(&handler);
|
|
Dart_Port port2 = PortMap::CreatePort(&handler);
|
|
EXPECT(PortMapTestPeer::IsActivePort(port1));
|
|
EXPECT(PortMapTestPeer::IsActivePort(port2));
|
|
|
|
// Uniqueness.
|
|
EXPECT_NE(port1, port2);
|
|
|
|
PortMap::ClosePort(port1);
|
|
EXPECT(!PortMapTestPeer::IsActivePort(port1));
|
|
EXPECT(PortMapTestPeer::IsActivePort(port2));
|
|
|
|
PortMap::ClosePort(port2);
|
|
EXPECT(!PortMapTestPeer::IsActivePort(port1));
|
|
EXPECT(!PortMapTestPeer::IsActivePort(port2));
|
|
}
|
|
|
|
TEST_CASE(PortMap_ClosePorts) {
|
|
PortTestMessageHandler handler;
|
|
Dart_Port port1 = PortMap::CreatePort(&handler);
|
|
Dart_Port port2 = PortMap::CreatePort(&handler);
|
|
EXPECT(PortMapTestPeer::IsActivePort(port1));
|
|
EXPECT(PortMapTestPeer::IsActivePort(port2));
|
|
|
|
// Close all ports at once.
|
|
PortMap::ClosePorts(&handler);
|
|
EXPECT(!PortMapTestPeer::IsActivePort(port1));
|
|
EXPECT(!PortMapTestPeer::IsActivePort(port2));
|
|
}
|
|
|
|
TEST_CASE(PortMap_CreateManyPorts) {
|
|
PortTestMessageHandler handler;
|
|
for (int i = 0; i < 32; i++) {
|
|
Dart_Port port = PortMap::CreatePort(&handler);
|
|
EXPECT(PortMapTestPeer::IsActivePort(port));
|
|
PortMap::ClosePort(port);
|
|
EXPECT(!PortMapTestPeer::IsActivePort(port));
|
|
}
|
|
}
|
|
|
|
TEST_CASE(PortMap_SetPortState) {
|
|
PortTestMessageHandler handler;
|
|
|
|
// Regular port.
|
|
Dart_Port port = PortMap::CreatePort(&handler);
|
|
EXPECT_NE(0, port);
|
|
EXPECT(PortMapTestPeer::IsActivePort(port));
|
|
EXPECT(!PortMapTestPeer::IsLivePort(port));
|
|
|
|
PortMap::SetPortState(port, PortMap::kLivePort);
|
|
EXPECT(PortMapTestPeer::IsActivePort(port));
|
|
EXPECT(PortMapTestPeer::IsLivePort(port));
|
|
|
|
// Inactive port.
|
|
PortMap::SetPortState(port, PortMap::kInactivePort);
|
|
EXPECT(PortMapTestPeer::IsActivePort(port));
|
|
EXPECT(!PortMapTestPeer::IsLivePort(port));
|
|
|
|
PortMap::ClosePort(port);
|
|
EXPECT(!PortMapTestPeer::IsActivePort(port));
|
|
EXPECT(!PortMapTestPeer::IsLivePort(port));
|
|
|
|
// Control port.
|
|
port = PortMap::CreatePort(&handler);
|
|
EXPECT_NE(0, port);
|
|
EXPECT(PortMapTestPeer::IsActivePort(port));
|
|
EXPECT(!PortMapTestPeer::IsLivePort(port));
|
|
|
|
PortMap::SetPortState(port, PortMap::kControlPort);
|
|
EXPECT(PortMapTestPeer::IsActivePort(port));
|
|
EXPECT(!PortMapTestPeer::IsLivePort(port));
|
|
|
|
PortMap::ClosePort(port);
|
|
EXPECT(!PortMapTestPeer::IsActivePort(port));
|
|
EXPECT(!PortMapTestPeer::IsLivePort(port));
|
|
}
|
|
|
|
TEST_CASE(PortMap_PostMessage) {
|
|
PortTestMessageHandler handler;
|
|
Dart_Port port = PortMap::CreatePort(&handler);
|
|
EXPECT_EQ(0, handler.notify_count);
|
|
|
|
const char* message = "msg";
|
|
intptr_t message_len = strlen(message) + 1;
|
|
|
|
EXPECT(PortMap::PostMessage(
|
|
Message::New(port, reinterpret_cast<uint8_t*>(Utils::StrDup(message)),
|
|
message_len, nullptr, Message::kNormalPriority)));
|
|
|
|
// Check that the message notify callback was called.
|
|
EXPECT_EQ(1, handler.notify_count);
|
|
PortMap::ClosePorts(&handler);
|
|
}
|
|
|
|
TEST_CASE(PortMap_PostIntegerMessage) {
|
|
PortTestMessageHandler handler;
|
|
Dart_Port port = PortMap::CreatePort(&handler);
|
|
EXPECT_EQ(0, handler.notify_count);
|
|
|
|
EXPECT(PortMap::PostMessage(
|
|
Message::New(port, Smi::New(42), Message::kNormalPriority)));
|
|
|
|
// Check that the message notify callback was called.
|
|
EXPECT_EQ(1, handler.notify_count);
|
|
PortMap::ClosePorts(&handler);
|
|
}
|
|
|
|
TEST_CASE(PortMap_PostNullMessage) {
|
|
PortTestMessageHandler handler;
|
|
Dart_Port port = PortMap::CreatePort(&handler);
|
|
EXPECT_EQ(0, handler.notify_count);
|
|
|
|
EXPECT(PortMap::PostMessage(
|
|
Message::New(port, Object::null(), Message::kNormalPriority)));
|
|
|
|
// Check that the message notify callback was called.
|
|
EXPECT_EQ(1, handler.notify_count);
|
|
PortMap::ClosePorts(&handler);
|
|
}
|
|
|
|
TEST_CASE(PortMap_PostMessageClosedPort) {
|
|
// Create a port id and make it invalid.
|
|
PortTestMessageHandler handler;
|
|
Dart_Port port = PortMap::CreatePort(&handler);
|
|
PortMap::ClosePort(port);
|
|
|
|
const char* message = "msg";
|
|
intptr_t message_len = strlen(message) + 1;
|
|
|
|
EXPECT(!PortMap::PostMessage(
|
|
Message::New(port, reinterpret_cast<uint8_t*>(Utils::StrDup(message)),
|
|
message_len, nullptr, Message::kNormalPriority)));
|
|
}
|
|
|
|
} // namespace dart
|