Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
a3863b65
Unverified
Commit
a3863b65
authored
May 18, 2021
by
Jonah Williams
Committed by
GitHub
May 18, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tools] support memory profiles from flutter drive (#82739)
parent
78ee9ccd
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
163 additions
and
114 deletions
+163
-114
perf_tests.dart
dev/devicelab/lib/tasks/perf_tests.dart
+3
-101
drive.dart
packages/flutter_tools/lib/src/commands/drive.dart
+7
-1
devtools_launcher.dart
packages/flutter_tools/lib/src/devtools_launcher.dart
+7
-1
drive_service.dart
packages/flutter_tools/lib/src/drive/drive_service.dart
+39
-9
web_driver_service.dart
packages/flutter_tools/lib/src/drive/web_driver_service.dart
+1
-0
resident_runner.dart
packages/flutter_tools/lib/src/resident_runner.dart
+10
-2
devtools_launcher_test.dart
...tter_tools/test/general.shard/devtools_launcher_test.dart
+39
-0
drive_service_test.dart
...er_tools/test/general.shard/drive/drive_service_test.dart
+57
-0
No files found.
dev/devicelab/lib/tasks/perf_tests.dart
View file @
a3863b65
...
...
@@ -1351,31 +1351,20 @@ class DevToolsMemoryTest {
_device
=
await
devices
.
workingDevice
;
await
_device
.
unlock
();
await
_launchApp
();
if
(
_observatoryUri
==
null
)
{
return
TaskResult
.
failure
(
'Observatory URI not found.'
);
}
await
_launchDevTools
();
await
flutter
(
'drive'
,
options:
<
String
>[
'--use-existing-app'
,
_observatoryUri
,
'-d'
,
_device
.
deviceId
,
'--screenshot'
,
hostAgent
.
dumpDirectory
.
path
,
'--profile'
,
'--profile-memory'
,
_kJsonFileName
,
'--no-publish-port'
,
'-v'
,
driverTest
,
],
);
_devToolsProcess
.
kill
();
await
_devToolsProcess
.
exitCode
;
_runProcess
.
kill
();
await
_runProcess
.
exitCode
;
final
Map
<
String
,
dynamic
>
data
=
json
.
decode
(
file
(
'
$project
/
$_kJsonFileName
'
).
readAsStringSync
(),
)
as
Map
<
String
,
dynamic
>;
...
...
@@ -1391,10 +1380,6 @@ class DevToolsMemoryTest {
}
}
await
flutter
(
'install'
,
options:
<
String
>[
'--uninstall-only'
,
]);
return
TaskResult
.
success
(
<
String
,
dynamic
>{
'maxRss'
:
maxRss
,
'maxAdbTotal'
:
maxAdbTotal
},
benchmarkScoreKeys:
<
String
>[
'maxRss'
,
'maxAdbTotal'
],
...
...
@@ -1402,90 +1387,7 @@ class DevToolsMemoryTest {
});
}
Future
<
void
>
_launchApp
()
async
{
print
(
'launching
$project$driverTest
on device...'
);
final
String
flutterPath
=
path
.
join
(
flutterDirectory
.
path
,
'bin'
,
'flutter'
);
_runProcess
=
await
startProcess
(
flutterPath
,
<
String
>[
'run'
,
'--verbose'
,
'--profile'
,
'--no-publish-port'
,
'-d'
,
_device
.
deviceId
,
driverTest
,
],
);
// Listen for Observatory URI and forward stdout/stderr
final
Completer
<
String
>
observatoryUri
=
Completer
<
String
>();
_runProcess
.
stdout
.
transform
<
String
>(
utf8
.
decoder
)
.
transform
<
String
>(
const
LineSplitter
())
.
listen
((
String
line
)
{
print
(
'run stdout:
$line
'
);
final
RegExpMatch
match
=
RegExp
(
r'An Observatory debugger and profiler on .+ is available at: ((http|//)[a-zA-Z0-9:/=_\-\.\[\]]+)'
).
firstMatch
(
line
);
if
(
match
!=
null
&&
!
observatoryUri
.
isCompleted
)
{
observatoryUri
.
complete
(
match
[
1
]);
_observatoryUri
=
match
[
1
];
}
},
onDone:
()
{
if
(!
observatoryUri
.
isCompleted
)
{
observatoryUri
.
complete
();
}
});
_forwardStream
(
_runProcess
.
stderr
,
'run stderr'
);
_observatoryUri
=
await
observatoryUri
.
future
;
}
Future
<
void
>
_launchDevTools
()
async
{
// To mitigate https://github.com/flutter/flutter/issues/82142
await
exec
(
pubBin
,
<
String
>[
'global'
,
'deactivate'
,
'devtools'
,
],
canFail:
true
);
// The version of devtools is pinned. If we pub global activate devtools and an
// upstream devtools release breaks our CI, it will manifest on an unrelated
// commit, making it more difficult to determine the cause.
//
// Also, for release branches, all external test dependencies need to be pinned.
await
exec
(
pubBin
,
<
String
>[
'global'
,
'activate'
,
'devtools'
,
'2.2.3'
,
// Try to debug https://github.com/flutter/flutter/issues/82142
'--verbose'
,
]);
_devToolsProcess
=
await
startProcess
(
pubBin
,
<
String
>[
'global'
,
'run'
,
'devtools'
,
'--vm-uri'
,
_observatoryUri
,
'--profile-memory'
,
_kJsonFileName
,
],
);
_forwardStream
(
_devToolsProcess
.
stdout
,
'devtools stdout'
);
_forwardStream
(
_devToolsProcess
.
stderr
,
'devtools stderr'
);
}
void
_forwardStream
(
Stream
<
List
<
int
>>
stream
,
String
label
)
{
stream
.
transform
<
String
>(
utf8
.
decoder
)
.
transform
<
String
>(
const
LineSplitter
())
.
listen
((
String
line
)
{
print
(
'
$label
:
$line
'
);
});
}
Device
_device
;
String
_observatoryUri
;
Process
_runProcess
;
Process
_devToolsProcess
;
static
const
String
_kJsonFileName
=
'devtools_memory.json'
;
}
...
...
packages/flutter_tools/lib/src/commands/drive.dart
View file @
a3863b65
...
...
@@ -21,6 +21,7 @@ import '../dart/package_map.dart';
import
'../device.dart'
;
import
'../drive/drive_service.dart'
;
import
'../globals.dart'
as
globals
;
import
'../resident_runner.dart'
;
import
'../runner/flutter_command.dart'
show
FlutterCommandResult
,
FlutterOptions
;
import
'../web/web_device.dart'
;
import
'run.dart'
;
...
...
@@ -143,7 +144,10 @@ class DriveCommand extends RunCommandBase {
help:
'Attempts to write an SkSL file when the drive process is finished '
'to the provided file, overwriting it if necessary.'
)
..
addMultiOption
(
'test-arguments'
,
help:
'Additional arguments to pass to the '
'Dart VM running The test script.'
);
'Dart VM running The test script.'
)
..
addOption
(
'profile-memory'
,
help:
'Launch devtools and profile application memory, writing '
'The output data to the file path provided to this argument as JSON.'
,
valueHelp:
'profile_memory.json'
);
}
// `pub` must always be run due to the test script running from source,
...
...
@@ -215,6 +219,7 @@ class DriveCommand extends RunCommandBase {
logger:
_logger
,
processUtils:
globals
.
processUtils
,
dartSdkPath:
globals
.
artifacts
.
getHostArtifact
(
HostArtifact
.
engineDartBinary
).
path
,
devtoolsLauncher:
DevtoolsLauncher
.
instance
,
);
final
PackageConfig
packageConfig
=
await
loadPackageConfigWithLogging
(
_fileSystem
.
file
(
'.packages'
),
...
...
@@ -271,6 +276,7 @@ class DriveCommand extends RunCommandBase {
?
int
.
tryParse
(
stringArg
(
'driver-port'
))
:
null
,
androidEmulator:
boolArg
(
'android-emulator'
),
profileMemory:
stringArg
(
'profile-memory'
),
);
if
(
testResult
!=
0
&&
screenshot
!=
null
)
{
await
takeScreenshot
(
device
,
screenshot
,
_fileSystem
,
_logger
,
_fsUtils
);
...
...
packages/flutter_tools/lib/src/devtools_launcher.dart
View file @
a3863b65
...
...
@@ -41,6 +41,7 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
final
Platform
_platform
;
final
PersistentToolState
_persistentToolState
;
final
io
.
HttpClient
_httpClient
;
final
Completer
<
void
>
_processStartCompleter
=
Completer
<
void
>();
io
.
Process
_devToolsProcess
;
...
...
@@ -49,7 +50,10 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
static
const
String
_pubHostedUrlKey
=
'PUB_HOSTED_URL'
;
@override
Future
<
void
>
launch
(
Uri
vmServiceUri
)
async
{
Future
<
void
>
get
processStart
=>
_processStartCompleter
.
future
;
@override
Future
<
void
>
launch
(
Uri
vmServiceUri
,
{
List
<
String
>
additionalArguments
})
async
{
// Place this entire method in a try/catch that swallows exceptions because
// this method is guaranteed not to return a Future that throws.
try
{
...
...
@@ -116,7 +120,9 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
'devtools'
,
'--no-launch-browser'
,
if
(
vmServiceUri
!=
null
)
'--vm-uri=
$vmServiceUri
'
,
...?
additionalArguments
,
]);
_processStartCompleter
.
complete
();
final
Completer
<
Uri
>
completer
=
Completer
<
Uri
>();
_devToolsProcess
.
stdout
.
transform
(
utf8
.
decoder
)
...
...
packages/flutter_tools/lib/src/drive/drive_service.dart
View file @
a3863b65
...
...
@@ -4,6 +4,8 @@
// @dart = 2.8
import
'dart:async'
;
import
'package:dds/dds.dart'
as
dds
;
import
'package:file/file.dart'
;
import
'package:meta/meta.dart'
;
...
...
@@ -16,6 +18,7 @@ import '../base/logger.dart';
import
'../base/process.dart'
;
import
'../build_info.dart'
;
import
'../device.dart'
;
import
'../resident_runner.dart'
;
import
'../sksl_writer.dart'
;
import
'../vmservice.dart'
;
import
'web_driver_service.dart'
;
...
...
@@ -26,15 +29,18 @@ class FlutterDriverFactory {
@required
Logger
logger
,
@required
ProcessUtils
processUtils
,
@required
String
dartSdkPath
,
@required
DevtoolsLauncher
devtoolsLauncher
,
})
:
_applicationPackageFactory
=
applicationPackageFactory
,
_logger
=
logger
,
_processUtils
=
processUtils
,
_dartSdkPath
=
dartSdkPath
;
_dartSdkPath
=
dartSdkPath
,
_devtoolsLauncher
=
devtoolsLauncher
;
final
ApplicationPackageFactory
_applicationPackageFactory
;
final
Logger
_logger
;
final
ProcessUtils
_processUtils
;
final
String
_dartSdkPath
;
final
DevtoolsLauncher
_devtoolsLauncher
;
/// Create a driver service for running `flutter drive`.
DriverService
createDriverService
(
bool
web
)
{
...
...
@@ -49,6 +55,7 @@ class FlutterDriverFactory {
processUtils:
_processUtils
,
dartSdkPath:
_dartSdkPath
,
applicationPackageFactory:
_applicationPackageFactory
,
devtoolsLauncher:
_devtoolsLauncher
,
);
}
}
...
...
@@ -78,6 +85,9 @@ abstract class DriverService {
/// Start the test file with the provided [arguments] and [environment], returning
/// the test process exit code.
///
/// if [profileMemory] is provided, it will be treated as a file path to write a
/// devtools memory profile.
Future
<
int
>
startTest
(
String
testFile
,
List
<
String
>
arguments
,
...
...
@@ -89,6 +99,7 @@ abstract class DriverService {
bool
androidEmulator
,
int
driverPort
,
List
<
String
>
browserDimension
,
String
profileMemory
,
});
/// Stop the running application and uninstall it from the device.
...
...
@@ -110,12 +121,14 @@ class FlutterDriverService extends DriverService {
@required
Logger
logger
,
@required
ProcessUtils
processUtils
,
@required
String
dartSdkPath
,
@required
DevtoolsLauncher
devtoolsLauncher
,
@visibleForTesting
VMServiceConnector
vmServiceConnector
=
connectToVmService
,
})
:
_applicationPackageFactory
=
applicationPackageFactory
,
_logger
=
logger
,
_processUtils
=
processUtils
,
_dartSdkPath
=
dartSdkPath
,
_vmServiceConnector
=
vmServiceConnector
;
_vmServiceConnector
=
vmServiceConnector
,
_devtoolsLauncher
=
devtoolsLauncher
;
static
const
int
_kLaunchAttempts
=
3
;
...
...
@@ -124,6 +137,7 @@ class FlutterDriverService extends DriverService {
final
ProcessUtils
_processUtils
;
final
String
_dartSdkPath
;
final
VMServiceConnector
_vmServiceConnector
;
final
DevtoolsLauncher
_devtoolsLauncher
;
Device
_device
;
ApplicationPackage
_applicationPackage
;
...
...
@@ -242,14 +256,30 @@ class FlutterDriverService extends DriverService {
bool
androidEmulator
,
int
driverPort
,
List
<
String
>
browserDimension
,
String
profileMemory
,
})
async
{
return
_processUtils
.
stream
(<
String
>[
_dartSdkPath
,
...<
String
>[...
arguments
,
testFile
,
'-rexpanded'
],
],
environment:
<
String
,
String
>{
'VM_SERVICE_URL'
:
_vmServiceUri
,
...
environment
,
});
if
(
profileMemory
!=
null
)
{
unawaited
(
_devtoolsLauncher
.
launch
(
Uri
.
parse
(
_vmServiceUri
),
additionalArguments:
<
String
>[
'--profile-memory=
$profileMemory
'
],
));
// When profiling memory the original launch future will never complete.
await
_devtoolsLauncher
.
processStart
;
}
try
{
final
int
result
=
await
_processUtils
.
stream
(<
String
>[
_dartSdkPath
,
...<
String
>[...
arguments
,
testFile
,
'-rexpanded'
],
],
environment:
<
String
,
String
>{
'VM_SERVICE_URL'
:
_vmServiceUri
,
...
environment
,
});
return
result
;
}
finally
{
if
(
profileMemory
!=
null
)
{
await
_devtoolsLauncher
.
close
();
}
}
}
@override
...
...
packages/flutter_tools/lib/src/drive/web_driver_service.dart
View file @
a3863b65
...
...
@@ -97,6 +97,7 @@ class WebDriverService extends DriverService {
bool
androidEmulator
,
int
driverPort
,
List
<
String
>
browserDimension
,
String
profileMemory
,
})
async
{
async_io
.
WebDriver
webDriver
;
final
Browser
browser
=
_browserNameToEnum
(
browserName
);
...
...
packages/flutter_tools/lib/src/resident_runner.dart
View file @
a3863b65
...
...
@@ -1802,13 +1802,21 @@ abstract class DevtoolsLauncher {
/// Launch a Dart DevTools process, optionally targeting a specific VM Service
/// URI if [vmServiceUri] is non-null.
///
/// [additionalArguments] may be optionally specified and are passed directly
/// to the devtools run command.
///
/// This method must return a future that is guaranteed not to fail, because it
/// will be used in unawaited contexts.
@visibleForTesting
Future
<
void
>
launch
(
Uri
vmServiceUri
);
Future
<
void
>
launch
(
Uri
vmServiceUri
,
{
List
<
String
>
additionalArguments
});
Future
<
void
>
close
();
/// When measuring devtools memory via addtional arguments, the launch process
/// will technically never complete.
///
/// Us this as an indicator that the process has started.
Future
<
void
>
processStart
;
/// Returns a future that completes when the DevTools server is ready.
///
/// Completes when [devToolsUrl] is set. That can be set either directly, or
...
...
packages/flutter_tools/test/general.shard/devtools_launcher_test.dart
View file @
a3863b65
...
...
@@ -275,6 +275,45 @@ void main() {
await
launcher
.
serve
();
});
testWithoutContext
(
'DevtoolsLauncher can launch devtools with a memory profile'
,
()
async
{
persistentToolState
.
lastDevToolsActivation
=
DateTime
.
now
();
final
FakeProcessManager
processManager
=
FakeProcessManager
.
list
(<
FakeCommand
>[
const
FakeCommand
(
command:
<
String
>[
'pub'
,
'global'
,
'list'
,
],
stdout:
'devtools 0.9.6'
,
),
const
FakeCommand
(
command:
<
String
>[
'pub'
,
'global'
,
'run'
,
'devtools'
,
'--no-launch-browser'
,
'--vm-uri=localhost:8181/abcdefg'
,
'--profile-memory=foo'
],
stdout:
'Serving DevTools at http://127.0.0.1:9100
\n
'
,
),
]);
final
DevtoolsLauncher
launcher
=
DevtoolsServerLauncher
(
pubExecutable:
'pub'
,
logger:
logger
,
platform:
platform
,
persistentToolState:
persistentToolState
,
httpClient:
FakeHttpClient
.
any
(),
processManager:
processManager
,
);
await
launcher
.
launch
(
Uri
.
parse
(
'localhost:8181/abcdefg'
),
additionalArguments:
<
String
>[
'--profile-memory=foo'
]);
expect
(
launcher
.
processStart
,
completes
);
expect
(
processManager
,
hasNoRemainingExpectations
);
});
testWithoutContext
(
'DevtoolsLauncher prints error if exception is thrown during activate'
,
()
async
{
final
DevtoolsLauncher
launcher
=
DevtoolsServerLauncher
(
pubExecutable:
'pub'
,
...
...
packages/flutter_tools/test/general.shard/drive/drive_service_test.dart
View file @
a3863b65
...
...
@@ -4,6 +4,8 @@
// @dart = 2.8
import
'dart:async'
;
import
'package:file/file.dart'
;
import
'package:file/memory.dart'
;
import
'package:flutter_tools/src/application_package.dart'
;
...
...
@@ -14,6 +16,7 @@ import 'package:flutter_tools/src/build_info.dart';
import
'package:flutter_tools/src/convert.dart'
;
import
'package:flutter_tools/src/device.dart'
;
import
'package:flutter_tools/src/drive/drive_service.dart'
;
import
'package:flutter_tools/src/resident_runner.dart'
;
import
'package:flutter_tools/src/version.dart'
;
import
'package:flutter_tools/src/vmservice.dart'
;
import
'package:meta/meta.dart'
;
...
...
@@ -182,6 +185,39 @@ void main() {
expect
(
testResult
,
23
);
});
testWithoutContext
(
'Connects to device VM Service and runs test application with devtools memory profile'
,
()
async
{
final
FakeVmServiceHost
fakeVmServiceHost
=
FakeVmServiceHost
(
requests:
<
FakeVmServiceRequest
>[
getVM
,
]);
final
FakeProcessManager
processManager
=
FakeProcessManager
.
list
(<
FakeCommand
>[
const
FakeCommand
(
command:
<
String
>[
'dart'
,
'--enable-experiment=non-nullable'
,
'foo.test'
,
'-rexpanded'
],
exitCode:
23
,
environment:
<
String
,
String
>{
'FOO'
:
'BAR'
,
'VM_SERVICE_URL'
:
'http://127.0.0.1:1234/'
// dds forwarded URI
},
),
]);
final
FakeDevtoolsLauncher
launcher
=
FakeDevtoolsLauncher
();
final
DriverService
driverService
=
setUpDriverService
(
processManager:
processManager
,
vmService:
fakeVmServiceHost
.
vmService
,
devtoolsLauncher:
launcher
);
final
Device
device
=
FakeDevice
(
LaunchResult
.
succeeded
(
observatoryUri:
Uri
.
parse
(
'http://127.0.0.1:63426/1UasC_ihpXY=/'
),
));
await
driverService
.
start
(
BuildInfo
.
profile
,
device
,
DebuggingOptions
.
enabled
(
BuildInfo
.
profile
),
true
);
final
int
testResult
=
await
driverService
.
startTest
(
'foo.test'
,
<
String
>[
'--enable-experiment=non-nullable'
],
<
String
,
String
>{
'FOO'
:
'BAR'
},
PackageConfig
(<
Package
>[
Package
(
'test'
,
Uri
.
base
)]),
profileMemory:
'devtools_memory.json'
,
);
expect
(
launcher
.
closed
,
true
);
expect
(
testResult
,
23
);
});
testWithoutContext
(
'Uses dart to execute the test if there is no package:test dependency'
,
()
async
{
final
FakeVmServiceHost
fakeVmServiceHost
=
FakeVmServiceHost
(
requests:
<
FakeVmServiceRequest
>[
getVM
,
...
...
@@ -424,6 +460,7 @@ FlutterDriverService setUpDriverService({
Logger
logger
,
ProcessManager
processManager
,
FlutterVmService
vmService
,
DevtoolsLauncher
devtoolsLauncher
,
})
{
logger
??=
BufferLogger
.
test
();
return
FlutterDriverService
(
...
...
@@ -434,6 +471,7 @@ FlutterDriverService setUpDriverService({
processManager:
processManager
??
FakeProcessManager
.
any
(),
),
dartSdkPath:
'dart'
,
devtoolsLauncher:
devtoolsLauncher
??
FakeDevtoolsLauncher
(),
vmServiceConnector:
(
Uri
httpUri
,
{
ReloadSources
reloadSources
,
Restart
restart
,
...
...
@@ -557,3 +595,22 @@ class FakeDartDevelopmentService extends Fake implements DartDevelopmentService
disposed
=
true
;
}
}
class
FakeDevtoolsLauncher
extends
Fake
implements
DevtoolsLauncher
{
bool
closed
=
false
;
final
Completer
<
void
>
_processStarted
=
Completer
<
void
>();
@override
Future
<
void
>
launch
(
Uri
vmServiceUri
,
{
List
<
String
>
additionalArguments
})
{
_processStarted
.
complete
();
return
Completer
<
void
>().
future
;
}
@override
Future
<
void
>
get
processStart
=>
_processStarted
.
future
;
@override
Future
<
void
>
close
()
async
{
closed
=
true
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment