Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
89358407
R
roslyn
项目概览
lwm1986
/
roslyn
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
roslyn
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
89358407
编写于
3月 16, 2020
作者:
M
msftbot[bot]
提交者:
GitHub
3月 16, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #42383 from CyrusNajmabadi/telemetryOOP
Move the project telemetry collection out of process.
上级
f9a78262
0a0f16aa
变更
18
隐藏空白更改
内联
并排
Showing
18 changed file
with
634 addition
and
321 deletion
+634
-321
eng/targets/GenerateServiceHubConfigurationFiles.targets
eng/targets/GenerateServiceHubConfigurationFiles.targets
+2
-1
src/EditorFeatures/TestUtilities/Remote/InProcRemostHostClient.cs
...orFeatures/TestUtilities/Remote/InProcRemostHostClient.cs
+1
-0
src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs
...DesignerAttribute/VisualStudioDesignerAttributeService.cs
+22
-72
src/VisualStudio/Core/Def/Implementation/ProjectTelemetry/IProjectTelemetryService.cs
...plementation/ProjectTelemetry/IProjectTelemetryService.cs
+23
-0
src/VisualStudio/Core/Def/Implementation/ProjectTelemetry/VisualStudioProjectTelemetryService.cs
...n/ProjectTelemetry/VisualStudioProjectTelemetryService.cs
+180
-0
src/VisualStudio/Core/Def/Implementation/ProjectTelemetry/VisualStudioProjectTelemetryServiceFactory.cs
...ctTelemetry/VisualStudioProjectTelemetryServiceFactory.cs
+34
-0
src/VisualStudio/Core/Def/RoslynPackage.cs
src/VisualStudio/Core/Def/RoslynPackage.cs
+6
-2
src/VisualStudio/Core/Def/Telemetry/ProjectTelemetryIncrementalAnalyzerProvider.cs
.../Telemetry/ProjectTelemetryIncrementalAnalyzerProvider.cs
+0
-246
src/VisualStudio/Setup/source.extension.vsixmanifest
src/VisualStudio/Setup/source.extension.vsixmanifest
+2
-0
src/Workspaces/Core/Portable/ProjectTelemetry/IProjectTelemetryServiceCallback.cs
...able/ProjectTelemetry/IProjectTelemetryServiceCallback.cs
+21
-0
src/Workspaces/Core/Portable/ProjectTelemetry/IRemoteProjectTelemetryService.cs
...rtable/ProjectTelemetry/IRemoteProjectTelemetryService.cs
+20
-0
src/Workspaces/Core/Portable/ProjectTelemetry/ProjectTelemetryInfo.cs
...es/Core/Portable/ProjectTelemetry/ProjectTelemetryInfo.cs
+30
-0
src/Workspaces/Core/Portable/Remote/WellKnownServiceHubServices.cs
...paces/Core/Portable/Remote/WellKnownServiceHubServices.cs
+2
-0
src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryIncrementalAnalyzer.cs
...ectTelemetry/RemoteProjectTelemetryIncrementalAnalyzer.cs
+85
-0
src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryIncrementalAnalyzerProvider.cs
...etry/RemoteProjectTelemetryIncrementalAnalyzerProvider.cs
+28
-0
src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryService.cs
...ervices/ProjectTelemetry/RemoteProjectTelemetryService.cs
+45
-0
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems
...sAndExtensions/Compiler/Core/CompilerExtensions.projitems
+1
-0
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AsyncBatchingWorkQueue.cs
...ensions/Compiler/Core/Utilities/AsyncBatchingWorkQueue.cs
+132
-0
未找到文件。
eng/targets/GenerateServiceHubConfigurationFiles.targets
浏览文件 @
89358407
...
@@ -10,6 +10,7 @@
...
@@ -10,6 +10,7 @@
<ServiceHubService
Include=
"roslynRemoteHost"
ClassName=
"Microsoft.CodeAnalysis.Remote.RemoteHostService"
/>
<ServiceHubService
Include=
"roslynRemoteHost"
ClassName=
"Microsoft.CodeAnalysis.Remote.RemoteHostService"
/>
<ServiceHubService
Include=
"roslynSnapshot"
ClassName=
"Microsoft.CodeAnalysis.Remote.SnapshotService"
/>
<ServiceHubService
Include=
"roslynSnapshot"
ClassName=
"Microsoft.CodeAnalysis.Remote.SnapshotService"
/>
<ServiceHubService
Include=
"roslynRemoteDesignerAttributeService"
ClassName=
"Microsoft.CodeAnalysis.Remote.RemoteDesignerAttributeService"
/>
<ServiceHubService
Include=
"roslynRemoteDesignerAttributeService"
ClassName=
"Microsoft.CodeAnalysis.Remote.RemoteDesignerAttributeService"
/>
<ServiceHubService
Include=
"roslynRemoteProjectTelemetryService"
ClassName=
"Microsoft.CodeAnalysis.Remote.RemoteProjectTelemetryService"
/>
<ServiceHubService
Include=
"roslynRemoteSymbolSearchUpdateEngine"
ClassName=
"Microsoft.CodeAnalysis.Remote.RemoteSymbolSearchUpdateEngine"
/>
<ServiceHubService
Include=
"roslynRemoteSymbolSearchUpdateEngine"
ClassName=
"Microsoft.CodeAnalysis.Remote.RemoteSymbolSearchUpdateEngine"
/>
<ServiceHubService
Include=
"roslynLanguageServer"
ClassName=
"Microsoft.CodeAnalysis.Remote.LanguageServer"
/>
<ServiceHubService
Include=
"roslynLanguageServer"
ClassName=
"Microsoft.CodeAnalysis.Remote.LanguageServer"
/>
</ItemGroup>
</ItemGroup>
...
@@ -56,4 +57,4 @@
...
@@ -56,4 +57,4 @@
<VSIXSourceItem
Include=
"@(_JsonFile->'%(Identity)')"
/>
<VSIXSourceItem
Include=
"@(_JsonFile->'%(Identity)')"
/>
</ItemGroup>
</ItemGroup>
</Target>
</Target>
</Project>
</Project>
\ No newline at end of file
src/EditorFeatures/TestUtilities/Remote/InProcRemostHostClient.cs
浏览文件 @
89358407
...
@@ -168,6 +168,7 @@ public InProcRemoteServices(bool runCacheCleanup)
...
@@ -168,6 +168,7 @@ public InProcRemoteServices(bool runCacheCleanup)
RegisterService
(
WellKnownServiceHubServices
.
SnapshotService
,
(
s
,
p
)
=>
new
SnapshotService
(
s
,
p
));
RegisterService
(
WellKnownServiceHubServices
.
SnapshotService
,
(
s
,
p
)
=>
new
SnapshotService
(
s
,
p
));
RegisterService
(
WellKnownServiceHubServices
.
RemoteSymbolSearchUpdateEngine
,
(
s
,
p
)
=>
new
RemoteSymbolSearchUpdateEngine
(
s
,
p
));
RegisterService
(
WellKnownServiceHubServices
.
RemoteSymbolSearchUpdateEngine
,
(
s
,
p
)
=>
new
RemoteSymbolSearchUpdateEngine
(
s
,
p
));
RegisterService
(
WellKnownServiceHubServices
.
RemoteDesignerAttributeService
,
(
s
,
p
)
=>
new
RemoteDesignerAttributeService
(
s
,
p
));
RegisterService
(
WellKnownServiceHubServices
.
RemoteDesignerAttributeService
,
(
s
,
p
)
=>
new
RemoteDesignerAttributeService
(
s
,
p
));
RegisterService
(
WellKnownServiceHubServices
.
RemoteProjectTelemetryService
,
(
s
,
p
)
=>
new
RemoteProjectTelemetryService
(
s
,
p
));
RegisterService
(
WellKnownServiceHubServices
.
LanguageServer
,
(
s
,
p
)
=>
new
LanguageServer
(
s
,
p
));
RegisterService
(
WellKnownServiceHubServices
.
LanguageServer
,
(
s
,
p
)
=>
new
LanguageServer
(
s
,
p
));
}
}
...
...
src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs
浏览文件 @
89358407
...
@@ -7,6 +7,7 @@
...
@@ -7,6 +7,7 @@
using
System
;
using
System
;
using
System.Collections.Concurrent
;
using
System.Collections.Concurrent
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Collections.Immutable
;
using
System.Linq
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
...
@@ -63,35 +64,7 @@ internal class VisualStudioDesignerAttributeService
...
@@ -63,35 +64,7 @@ internal class VisualStudioDesignerAttributeService
// We'll get notifications from the OOP server about new attribute arguments. Batch those
// We'll get notifications from the OOP server about new attribute arguments. Batch those
// notifications up and deliver them to VS every second.
// notifications up and deliver them to VS every second.
#
region
protected
by
lock
private
AsyncBatchingWorkQueue
<
DesignerInfo
>
_workQueue
=
null
!;
/// <summary>
/// Lock we will use to ensure the remainder of these fields can be accessed in a threadsafe
/// manner. When OOP calls back into us, we'll place the data it produced into
/// <see cref="_updatedInfos"/>. We'll then kick of a task to process this in the future if
/// we don't already have an existing task in flight for that.
/// </summary>
private
readonly
object
_gate
=
new
object
();
/// <summary>
/// Data produced by OOP that we want to process in our next update task.
/// </summary>
private
readonly
List
<
DesignerInfo
>
_updatedInfos
=
new
List
<
DesignerInfo
>();
/// <summary>
/// Task kicked off to do the next batch of processing of <see cref="_updatedInfos"/>. These
/// tasks form a chain so that the next task only processes when the previous one completes.
/// </summary>
private
Task
_updateTask
=
Task
.
CompletedTask
;
/// <summary>
/// Whether or not there is an existing task in flight that will process the current batch
/// of <see cref="_updatedInfos"/>. If there is an existing in flight task, we don't need
/// to kick off a new one if we receive more notifications before it runs.
/// </summary>
private
bool
_taskInFlight
=
false
;
#
endregion
public
VisualStudioDesignerAttributeService
(
public
VisualStudioDesignerAttributeService
(
VisualStudioWorkspaceImpl
workspace
,
VisualStudioWorkspaceImpl
workspace
,
...
@@ -117,6 +90,11 @@ void IDesignerAttributeService.Start(CancellationToken cancellationToken)
...
@@ -117,6 +90,11 @@ void IDesignerAttributeService.Start(CancellationToken cancellationToken)
private
async
Task
StartAsync
(
CancellationToken
cancellationToken
)
private
async
Task
StartAsync
(
CancellationToken
cancellationToken
)
{
{
_workQueue
=
new
AsyncBatchingWorkQueue
<
DesignerInfo
>(
TimeSpan
.
FromSeconds
(
1
),
this
.
NotifyProjectSystemAsync
,
cancellationToken
);
// Have to catch all exceptions coming through here as this is called from a
// Have to catch all exceptions coming through here as this is called from a
// fire-and-forget method and we want to make sure nothing leaks out.
// fire-and-forget method and we want to make sure nothing leaks out.
try
try
...
@@ -159,42 +137,23 @@ private async Task StartWorkerAsync(CancellationToken cancellationToken)
...
@@ -159,42 +137,23 @@ private async Task StartWorkerAsync(CancellationToken cancellationToken)
/// <summary>
/// <summary>
/// Callback from the OOP service back into us.
/// Callback from the OOP service back into us.
/// </summary>
/// </summary>
public
Task
RegisterDesignerAttributesAsync
(
public
Task
RegisterDesignerAttributesAsync
(
IList
<
DesignerInfo
>
attributeInfos
,
CancellationToken
cancellationToken
)
IList
<
DesignerInfo
>
attributeInfos
,
CancellationToken
cancellationToken
)
{
{
lock
(
_gate
)
_workQueue
.
AddWork
(
attributeInfos
);
{
// add our work to the set we'll process in the next batch.
_updatedInfos
.
AddRange
(
attributeInfos
);
if
(!
_taskInFlight
)
{
// No in-flight task. Kick one off to process these messages a second from now.
// We always attach the task to the previous one so that notifications to the ui
// follow the same order as the notification the OOP server sent to us.
_updateTask
=
_updateTask
.
ContinueWithAfterDelayFromAsync
(
_
=>
NotifyProjectSystemAsync
(
cancellationToken
),
cancellationToken
,
1000
/*ms*/
,
TaskContinuationOptions
.
RunContinuationsAsynchronously
,
TaskScheduler
.
Default
);
_taskInFlight
=
true
;
}
}
return
Task
.
CompletedTask
;
return
Task
.
CompletedTask
;
}
}
private
async
Task
NotifyProjectSystemAsync
(
CancellationToken
cancellationToken
)
private
async
Task
NotifyProjectSystemAsync
(
ImmutableArray
<
DesignerInfo
>
infos
,
CancellationToken
cancellationToken
)
{
{
cancellationToken
.
ThrowIfCancellationRequested
();
cancellationToken
.
ThrowIfCancellationRequested
();
using
var
_1
=
ArrayBuilder
<
DesignerInfo
>.
GetInstance
(
out
var
attribute
Infos
);
using
var
_1
=
ArrayBuilder
<
DesignerInfo
>.
GetInstance
(
out
var
filtered
Infos
);
Add
InfosAndResetQueue
(
attribute
Infos
);
Add
FilteredInfos
(
infos
,
filtered
Infos
);
// Now, group all the notifications by project and update all the projects in parallel.
// Now, group all the notifications by project and update all the projects in parallel.
using
var
_2
=
ArrayBuilder
<
Task
>.
GetInstance
(
out
var
tasks
);
using
var
_2
=
ArrayBuilder
<
Task
>.
GetInstance
(
out
var
tasks
);
foreach
(
var
group
in
attribute
Infos
.
GroupBy
(
a
=>
a
.
DocumentId
.
ProjectId
))
foreach
(
var
group
in
filtered
Infos
.
GroupBy
(
a
=>
a
.
DocumentId
.
ProjectId
))
{
{
cancellationToken
.
ThrowIfCancellationRequested
();
cancellationToken
.
ThrowIfCancellationRequested
();
tasks
.
Add
(
NotifyProjectSystemAsync
(
group
.
Key
,
group
,
cancellationToken
));
tasks
.
Add
(
NotifyProjectSystemAsync
(
group
.
Key
,
group
,
cancellationToken
));
...
@@ -204,27 +163,18 @@ private async Task NotifyProjectSystemAsync(CancellationToken cancellationToken)
...
@@ -204,27 +163,18 @@ private async Task NotifyProjectSystemAsync(CancellationToken cancellationToken)
await
Task
.
WhenAll
(
tasks
).
ConfigureAwait
(
false
);
await
Task
.
WhenAll
(
tasks
).
ConfigureAwait
(
false
);
}
}
private
void
Add
InfosAndResetQueue
(
ArrayBuilder
<
DesignerInfo
>
attribute
Infos
)
private
void
Add
FilteredInfos
(
ImmutableArray
<
DesignerInfo
>
infos
,
ArrayBuilder
<
DesignerInfo
>
filtered
Infos
)
{
{
using
var
_
=
PooledHashSet
<
DocumentId
>.
GetInstance
(
out
var
seenDocumentIds
);
using
var
_
=
PooledHashSet
<
DocumentId
>.
GetInstance
(
out
var
seenDocumentIds
);
lock
(
_gate
)
// Walk the list of designer items in reverse, and skip any items for a project once
// we've already seen it once. That way, we're only reporting the most up to date
// information for a project, and we're skipping the stale information.
for
(
var
i
=
infos
.
Length
-
1
;
i
>=
0
;
i
--)
{
{
// walk the set of updates in reverse, and ignore documents if we see them a second
var
info
=
infos
[
i
];
// time. This ensures that if we're batching up multiple notifications for the same
if
(
seenDocumentIds
.
Add
(
info
.
DocumentId
))
// document, that we only bother processing the last one since it should beat out
filteredInfos
.
Add
(
info
);
// all the prior ones.
for
(
var
i
=
_updatedInfos
.
Count
-
1
;
i
>=
0
;
i
--)
{
var
designerArg
=
_updatedInfos
[
i
];
if
(
seenDocumentIds
.
Add
(
designerArg
.
DocumentId
))
attributeInfos
.
Add
(
designerArg
);
}
// mark there being no existing update task so that the next OOP notification will
// kick one off.
_updatedInfos
.
Clear
();
_taskInFlight
=
false
;
}
}
}
}
...
...
src/VisualStudio/Core/Def/Implementation/ProjectTelemetry/IProjectTelemetryService.cs
0 → 100644
浏览文件 @
89358407
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System.Threading
;
using
Microsoft.CodeAnalysis.Host
;
namespace
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectTelemetry
{
/// <summary>
/// In process service responsible for listening to OOP telemetry notifications.
/// </summary>
internal
interface
IProjectTelemetryService
:
IWorkspaceService
{
/// <summary>
/// Called by a host to let this service know that it should start background
/// analysis of the workspace to determine project telemetry.
/// </summary>
void
Start
(
CancellationToken
cancellationToken
);
}
}
src/VisualStudio/Core/Def/Implementation/ProjectTelemetry/VisualStudioProjectTelemetryService.cs
0 → 100644
浏览文件 @
89358407
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System
;
using
System.Collections.Immutable
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis.Editor.Shared.Utilities
;
using
Microsoft.CodeAnalysis.ErrorReporting
;
using
Microsoft.CodeAnalysis.PooledObjects
;
using
Microsoft.CodeAnalysis.ProjectTelemetry
;
using
Microsoft.CodeAnalysis.Remote
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Microsoft.Internal.VisualStudio.Shell
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
;
using
Roslyn.Utilities
;
namespace
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectTelemetry
{
internal
class
VisualStudioProjectTelemetryService
:
ForegroundThreadAffinitizedObject
,
IProjectTelemetryService
,
IProjectTelemetryServiceCallback
{
private
const
string
EventPrefix
=
"VS/Compilers/Compilation/"
;
private
const
string
PropertyPrefix
=
"VS.Compilers.Compilation.Inputs."
;
private
const
string
TelemetryEventPath
=
EventPrefix
+
"Inputs"
;
private
const
string
TelemetryExceptionEventPath
=
EventPrefix
+
"TelemetryUnhandledException"
;
private
const
string
TelemetryProjectIdName
=
PropertyPrefix
+
"ProjectId"
;
private
const
string
TelemetryProjectGuidName
=
PropertyPrefix
+
"ProjectGuid"
;
private
const
string
TelemetryLanguageName
=
PropertyPrefix
+
"Language"
;
private
const
string
TelemetryAnalyzerReferencesCountName
=
PropertyPrefix
+
"AnalyzerReferences.Count"
;
private
const
string
TelemetryProjectReferencesCountName
=
PropertyPrefix
+
"ProjectReferences.Count"
;
private
const
string
TelemetryMetadataReferencesCountName
=
PropertyPrefix
+
"MetadataReferences.Count"
;
private
const
string
TelemetryDocumentsCountName
=
PropertyPrefix
+
"Documents.Count"
;
private
const
string
TelemetryAdditionalDocumentsCountName
=
PropertyPrefix
+
"AdditionalDocuments.Count"
;
private
readonly
VisualStudioWorkspaceImpl
_workspace
;
/// <summary>
/// Our connections to the remote OOP server. Created on demand when we startup and then
/// kept around for the lifetime of this service.
/// </summary>
private
KeepAliveSession
?
_keepAliveSession
;
/// <summary>
/// Queue where we enqueue the information we get from OOP to process in batch in the future.
/// </summary>
private
AsyncBatchingWorkQueue
<
ProjectTelemetryInfo
>
_workQueue
=
null
!;
public
VisualStudioProjectTelemetryService
(
VisualStudioWorkspaceImpl
workspace
,
IThreadingContext
threadingContext
)
:
base
(
threadingContext
)
=>
_workspace
=
workspace
;
void
IProjectTelemetryService
.
Start
(
CancellationToken
cancellationToken
)
=>
_
=
StartAsync
(
cancellationToken
);
private
async
Task
StartAsync
(
CancellationToken
cancellationToken
)
{
// Have to catch all exceptions coming through here as this is called from a
// fire-and-forget method and we want to make sure nothing leaks out.
try
{
await
StartWorkerAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
}
catch
(
OperationCanceledException
)
{
// Cancellation is normal (during VS closing). Just ignore.
}
catch
(
Exception
e
)
when
(
FatalError
.
ReportWithoutCrash
(
e
))
{
// Otherwise report a watson for any other exception. Don't bring down VS. This is
// a BG service we don't want impacting the user experience.
}
}
private
async
Task
StartWorkerAsync
(
CancellationToken
cancellationToken
)
{
_workQueue
=
new
AsyncBatchingWorkQueue
<
ProjectTelemetryInfo
>(
TimeSpan
.
FromSeconds
(
1
),
NotifyTelemetryServiceAsync
,
cancellationToken
);
var
client
=
await
RemoteHostClient
.
TryGetClientAsync
(
_workspace
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
client
==
null
)
return
;
// Pass ourselves in as the callback target for the OOP service. As it discovers
// designer attributes it will call back into us to notify VS about it.
_keepAliveSession
=
await
client
.
TryCreateKeepAliveSessionAsync
(
WellKnownServiceHubServices
.
RemoteProjectTelemetryService
,
callbackTarget
:
this
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
_keepAliveSession
==
null
)
return
;
// Now kick off scanning in the OOP process.
var
success
=
await
_keepAliveSession
.
TryInvokeAsync
(
nameof
(
IRemoteProjectTelemetryService
.
ComputeProjectTelemetryAsync
),
solution
:
null
,
arguments
:
Array
.
Empty
<
object
>(),
cancellationToken
).
ConfigureAwait
(
false
);
}
/// <summary>
/// Callback from the OOP service back into us.
/// </summary>
public
Task
RegisterProjectTelemetryInfoAsync
(
ProjectTelemetryInfo
info
,
CancellationToken
cancellationToken
)
{
_workQueue
.
AddWork
(
info
);
return
Task
.
CompletedTask
;
}
private
async
Task
NotifyTelemetryServiceAsync
(
ImmutableArray
<
ProjectTelemetryInfo
>
infos
,
CancellationToken
cancellationToken
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
using
var
_1
=
ArrayBuilder
<
ProjectTelemetryInfo
>.
GetInstance
(
out
var
filteredInfos
);
AddFilteredInfos
(
infos
,
filteredInfos
);
using
var
_2
=
ArrayBuilder
<
Task
>.
GetInstance
(
out
var
tasks
);
foreach
(
var
info
in
filteredInfos
)
tasks
.
Add
(
Task
.
Run
(()
=>
NotifyTelemetryService
(
info
),
cancellationToken
));
await
Task
.
WhenAll
(
tasks
).
ConfigureAwait
(
false
);
}
private
void
AddFilteredInfos
(
ImmutableArray
<
ProjectTelemetryInfo
>
infos
,
ArrayBuilder
<
ProjectTelemetryInfo
>
filteredInfos
)
{
using
var
_
=
PooledHashSet
<
ProjectId
>.
GetInstance
(
out
var
seenProjectIds
);
// Walk the list of telemetry items in reverse, and skip any items for a project once
// we've already seen it once. That way, we're only reporting the most up to date
// information for a project, and we're skipping the stale information.
for
(
var
i
=
infos
.
Length
-
1
;
i
>=
0
;
i
--)
{
var
info
=
infos
[
i
];
if
(
seenProjectIds
.
Add
(
info
.
ProjectId
))
filteredInfos
.
Add
(
info
);
}
}
private
void
NotifyTelemetryService
(
ProjectTelemetryInfo
info
)
{
try
{
var
telemetryEvent
=
TelemetryHelper
.
TelemetryService
.
CreateEvent
(
TelemetryEventPath
);
telemetryEvent
.
SetStringProperty
(
TelemetryProjectIdName
,
info
.
ProjectId
.
Id
.
ToString
());
telemetryEvent
.
SetStringProperty
(
TelemetryProjectGuidName
,
Guid
.
Empty
.
ToString
());
telemetryEvent
.
SetStringProperty
(
TelemetryLanguageName
,
info
.
Language
);
telemetryEvent
.
SetIntProperty
(
TelemetryAnalyzerReferencesCountName
,
info
.
AnalyzerReferencesCount
);
telemetryEvent
.
SetIntProperty
(
TelemetryProjectReferencesCountName
,
info
.
ProjectReferencesCount
);
telemetryEvent
.
SetIntProperty
(
TelemetryMetadataReferencesCountName
,
info
.
MetadataReferencesCount
);
telemetryEvent
.
SetIntProperty
(
TelemetryDocumentsCountName
,
info
.
DocumentsCount
);
telemetryEvent
.
SetIntProperty
(
TelemetryAdditionalDocumentsCountName
,
info
.
AdditionalDocumentsCount
);
TelemetryHelper
.
DefaultTelemetrySession
.
PostEvent
(
telemetryEvent
);
}
catch
(
Exception
e
)
{
// The telemetry service itself can throw.
// So, to be very careful, put this in a try/catch too.
try
{
var
exceptionEvent
=
TelemetryHelper
.
TelemetryService
.
CreateEvent
(
TelemetryExceptionEventPath
);
exceptionEvent
.
SetStringProperty
(
"Type"
,
e
.
GetTypeDisplayName
());
exceptionEvent
.
SetStringProperty
(
"Message"
,
e
.
Message
);
exceptionEvent
.
SetStringProperty
(
"StackTrace"
,
e
.
StackTrace
);
TelemetryHelper
.
DefaultTelemetrySession
.
PostEvent
(
exceptionEvent
);
}
catch
{
}
}
}
}
}
src/VisualStudio/Core/Def/Implementation/ProjectTelemetry/VisualStudioProjectTelemetryServiceFactory.cs
0 → 100644
浏览文件 @
89358407
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System
;
using
System.Composition
;
using
Microsoft.CodeAnalysis.Editor.Shared.Utilities
;
using
Microsoft.CodeAnalysis.Host
;
using
Microsoft.CodeAnalysis.Host.Mef
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
;
namespace
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectTelemetry
{
[
ExportWorkspaceServiceFactory
(
typeof
(
IProjectTelemetryService
),
ServiceLayer
.
Host
),
Shared
]
internal
class
VisualStudioProjectTelemetryServiceFactory
:
IWorkspaceServiceFactory
{
private
readonly
IThreadingContext
_threadingContext
;
[
ImportingConstructor
]
[
Obsolete
(
MefConstruction
.
ImportingConstructorMessage
,
error
:
true
)]
public
VisualStudioProjectTelemetryServiceFactory
(
IThreadingContext
threadingContext
)
=>
_threadingContext
=
threadingContext
;
public
IWorkspaceService
?
CreateService
(
HostWorkspaceServices
workspaceServices
)
{
if
(!(
workspaceServices
.
Workspace
is
VisualStudioWorkspaceImpl
workspace
))
return
null
;
return
new
VisualStudioProjectTelemetryService
(
workspace
,
_threadingContext
);
}
}
}
src/VisualStudio/Core/Def/RoslynPackage.cs
浏览文件 @
89358407
...
@@ -4,7 +4,6 @@
...
@@ -4,7 +4,6 @@
using
System
;
using
System
;
using
System.ComponentModel.Design
;
using
System.ComponentModel.Design
;
using
System.Reflection
;
using
System.Runtime.InteropServices
;
using
System.Runtime.InteropServices
;
using
System.Threading
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
...
@@ -28,6 +27,7 @@
...
@@ -28,6 +27,7 @@
using
Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.RuleSets
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.RuleSets
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectTelemetry
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource
;
using
Microsoft.VisualStudio.LanguageServices.Telemetry
;
using
Microsoft.VisualStudio.LanguageServices.Telemetry
;
using
Microsoft.VisualStudio.PlatformUI
;
using
Microsoft.VisualStudio.PlatformUI
;
...
@@ -158,8 +158,12 @@ private async Task LoadComponentsBackgroundAsync(CancellationToken cancellationT
...
@@ -158,8 +158,12 @@ private async Task LoadComponentsBackgroundAsync(CancellationToken cancellationT
// Load the designer attribute service and tell it to start watching the solution for
// Load the designer attribute service and tell it to start watching the solution for
// designable files.
// designable files.
var
designerAttributeService
=
_workspace
.
Services
.
GetService
<
IDesignerAttributeService
>();
var
designerAttributeService
=
_workspace
.
Services
.
Get
Required
Service
<
IDesignerAttributeService
>();
designerAttributeService
.
Start
(
this
.
DisposalToken
);
designerAttributeService
.
Start
(
this
.
DisposalToken
);
// Load the telemetry service and tell it to start watching the solution for project info.
var
projectTelemetryService
=
_workspace
.
Services
.
GetRequiredService
<
IProjectTelemetryService
>();
projectTelemetryService
.
Start
(
this
.
DisposalToken
);
}
}
private
async
Task
LoadInteractiveMenusAsync
(
CancellationToken
cancellationToken
)
private
async
Task
LoadInteractiveMenusAsync
(
CancellationToken
cancellationToken
)
...
...
src/VisualStudio/Core/Def/Telemetry/ProjectTelemetryIncrementalAnalyzerProvider.cs
已删除
100644 → 0
浏览文件 @
f9a78262
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using
System
;
using
System.Collections.Generic
;
using
System.Composition
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis.Options
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Microsoft.CodeAnalysis.SolutionCrawler
;
using
Microsoft.Internal.VisualStudio.Shell
;
using
Microsoft.Internal.VisualStudio.Shell.Interop
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
;
namespace
Microsoft.VisualStudio.LanguageServices.Telemetry
{
/// <summary>
/// Creates an <see cref="IIncrementalAnalyzer"/> that collects basic information on <see cref="Project"/> inputs
/// and reports it to the <see cref="IVsTelemetryService"/>.
/// </summary>
/// <remarks>
/// This includes data such an source file counts, project, metadata, and analyzer reference counts, and so on.
/// </remarks>
[
ExportIncrementalAnalyzerProvider
(
nameof
(
ProjectTelemetryIncrementalAnalyzerProvider
),
new
[]
{
WorkspaceKind
.
Host
}),
Shared
]
internal
sealed
class
ProjectTelemetryIncrementalAnalyzerProvider
:
IIncrementalAnalyzerProvider
{
[
ImportingConstructor
]
public
ProjectTelemetryIncrementalAnalyzerProvider
()
{
}
public
IIncrementalAnalyzer
CreateIncrementalAnalyzer
(
Microsoft
.
CodeAnalysis
.
Workspace
workspace
)
{
return
new
Analyzer
();
}
private
sealed
class
Analyzer
:
IIncrementalAnalyzer
{
/// <summary>
/// For a given <see cref="ProjectId"/>, stores the most recent set of data reported to the
/// telemetry service.
/// </summary>
private
sealed
class
Cache
{
private
class
Inputs
{
public
string
Language
;
public
int
AnalyzerReferencesCount
;
public
int
ProjectReferencesCount
;
public
int
MetadataReferencesCount
;
public
int
DocumentsCount
;
public
int
AdditionalDocumentsCount
;
public
Inputs
(
string
language
,
int
analyzerReferencesCount
,
int
projectReferencesCount
,
int
metadataReferencesCount
,
int
documentsCount
,
int
additionalDocumentsCount
)
{
this
.
Language
=
language
;
this
.
AnalyzerReferencesCount
=
analyzerReferencesCount
;
this
.
ProjectReferencesCount
=
projectReferencesCount
;
this
.
MetadataReferencesCount
=
metadataReferencesCount
;
this
.
DocumentsCount
=
documentsCount
;
this
.
AdditionalDocumentsCount
=
additionalDocumentsCount
;
}
public
bool
Equals
(
Inputs
other
)
{
return
this
.
Language
.
Equals
(
other
.
Language
)
&&
this
.
AnalyzerReferencesCount
==
other
.
AnalyzerReferencesCount
&&
this
.
ProjectReferencesCount
==
other
.
ProjectReferencesCount
&&
this
.
MetadataReferencesCount
==
other
.
MetadataReferencesCount
&&
this
.
DocumentsCount
==
other
.
DocumentsCount
&&
this
.
AdditionalDocumentsCount
==
other
.
AdditionalDocumentsCount
;
}
}
private
readonly
object
_lockObject
=
new
object
();
private
readonly
Dictionary
<
ProjectId
,
Inputs
>
_items
=
new
Dictionary
<
ProjectId
,
Inputs
>();
/// <summary>
/// Adds or updates the data for the <see cref="Project"/> indicated by <paramref name="projectId"/>.
/// </summary>
/// <returns>
/// True if the data was added or updated, false if the data matches what is already in the cache.
/// </returns>
public
bool
TryAddOrUpdate
(
ProjectId
projectId
,
string
language
,
int
analyzerReferenceCount
,
int
projectReferencesCount
,
int
metadataReferencesCount
,
int
documentsCount
,
int
additionalDocumentsCount
)
{
lock
(
_lockObject
)
{
var
newInputs
=
new
Inputs
(
language
,
analyzerReferenceCount
,
projectReferencesCount
,
metadataReferencesCount
,
documentsCount
,
additionalDocumentsCount
);
if
(!
_items
.
TryGetValue
(
projectId
,
out
var
existingInputs
)
||
!
existingInputs
.
Equals
(
newInputs
))
{
_items
[
projectId
]
=
newInputs
;
return
true
;
}
return
false
;
}
}
/// <summary>
/// Removes all data associated with <paramref name="projectId"/>.
/// </summary>
public
void
Remove
(
ProjectId
projectId
)
{
lock
(
_lockObject
)
{
_items
.
Remove
(
projectId
);
}
}
}
private
const
string
EventPrefix
=
"VS/Compilers/Compilation/"
;
private
const
string
PropertyPrefix
=
"VS.Compilers.Compilation.Inputs."
;
private
const
string
TelemetryEventPath
=
EventPrefix
+
"Inputs"
;
private
const
string
TelemetryExceptionEventPath
=
EventPrefix
+
"TelemetryUnhandledException"
;
private
const
string
TelemetryProjectIdName
=
PropertyPrefix
+
"ProjectId"
;
private
const
string
TelemetryProjectGuidName
=
PropertyPrefix
+
"ProjectGuid"
;
private
const
string
TelemetryLanguageName
=
PropertyPrefix
+
"Language"
;
private
const
string
TelemetryAnalyzerReferencesCountName
=
PropertyPrefix
+
"AnalyzerReferences.Count"
;
private
const
string
TelemetryProjectReferencesCountName
=
PropertyPrefix
+
"ProjectReferences.Count"
;
private
const
string
TelemetryMetadataReferencesCountName
=
PropertyPrefix
+
"MetadataReferences.Count"
;
private
const
string
TelemetryDocumentsCountName
=
PropertyPrefix
+
"Documents.Count"
;
private
const
string
TelemetryAdditionalDocumentsCountName
=
PropertyPrefix
+
"AdditionalDocuments.Count"
;
private
readonly
Cache
_cache
=
new
Cache
();
public
Task
AnalyzeDocumentAsync
(
Document
document
,
SyntaxNode
bodyOpt
,
InvocationReasons
reasons
,
CancellationToken
cancellationToken
)
{
return
Task
.
CompletedTask
;
}
/// <summary>
/// Collects data from <paramref name="project"/> and reports it to the telemetry service.
/// </summary>
/// <remarks>
/// Only sends data to the telemetry service when one of the collected data points changes,
/// not necessarily every time this code is called.
/// </remarks>
public
Task
AnalyzeProjectAsync
(
Project
project
,
bool
semanticsChanged
,
InvocationReasons
reasons
,
CancellationToken
cancellationToken
)
{
if
(!
semanticsChanged
)
{
return
Task
.
CompletedTask
;
}
var
projectId
=
project
.
Id
;
var
language
=
project
.
Language
;
var
analyzerReferencesCount
=
project
.
AnalyzerReferences
.
Count
;
var
projectReferencesCount
=
project
.
AllProjectReferences
.
Count
;
var
metadataReferencesCount
=
project
.
MetadataReferences
.
Count
;
var
documentsCount
=
project
.
DocumentIds
.
Count
;
var
additionalDocumentsCount
=
project
.
AdditionalDocumentIds
.
Count
;
if
(
_cache
.
TryAddOrUpdate
(
projectId
,
language
,
analyzerReferencesCount
,
projectReferencesCount
,
metadataReferencesCount
,
documentsCount
,
additionalDocumentsCount
))
{
try
{
var
workspace
=
(
VisualStudioWorkspaceImpl
)
project
.
Solution
.
Workspace
;
var
telemetryEvent
=
TelemetryHelper
.
TelemetryService
.
CreateEvent
(
TelemetryEventPath
);
telemetryEvent
.
SetStringProperty
(
TelemetryProjectIdName
,
projectId
.
Id
.
ToString
());
// TODO: reconnect project GUID
telemetryEvent
.
SetStringProperty
(
TelemetryProjectGuidName
,
Guid
.
Empty
.
ToString
());
telemetryEvent
.
SetStringProperty
(
TelemetryLanguageName
,
language
);
telemetryEvent
.
SetIntProperty
(
TelemetryAnalyzerReferencesCountName
,
analyzerReferencesCount
);
telemetryEvent
.
SetIntProperty
(
TelemetryProjectReferencesCountName
,
projectReferencesCount
);
telemetryEvent
.
SetIntProperty
(
TelemetryMetadataReferencesCountName
,
metadataReferencesCount
);
telemetryEvent
.
SetIntProperty
(
TelemetryDocumentsCountName
,
documentsCount
);
telemetryEvent
.
SetIntProperty
(
TelemetryAdditionalDocumentsCountName
,
additionalDocumentsCount
);
TelemetryHelper
.
DefaultTelemetrySession
.
PostEvent
(
telemetryEvent
);
}
catch
(
Exception
e
)
{
// The telemetry service itself can throw.
// So, to be very careful, put this in a try/catch too.
try
{
var
exceptionEvent
=
TelemetryHelper
.
TelemetryService
.
CreateEvent
(
TelemetryExceptionEventPath
);
exceptionEvent
.
SetStringProperty
(
"Type"
,
e
.
GetTypeDisplayName
());
exceptionEvent
.
SetStringProperty
(
"Message"
,
e
.
Message
);
exceptionEvent
.
SetStringProperty
(
"StackTrace"
,
e
.
StackTrace
);
TelemetryHelper
.
DefaultTelemetrySession
.
PostEvent
(
exceptionEvent
);
}
catch
{
}
}
}
return
Task
.
CompletedTask
;
}
public
Task
AnalyzeSyntaxAsync
(
Document
document
,
InvocationReasons
reasons
,
CancellationToken
cancellationToken
)
{
return
Task
.
CompletedTask
;
}
public
Task
DocumentOpenAsync
(
Document
document
,
CancellationToken
cancellationToken
)
{
return
Task
.
CompletedTask
;
}
public
Task
DocumentCloseAsync
(
Document
document
,
CancellationToken
cancellationToken
)
{
return
Task
.
CompletedTask
;
}
public
Task
DocumentResetAsync
(
Document
document
,
CancellationToken
cancellationToken
)
{
return
Task
.
CompletedTask
;
}
public
bool
NeedsReanalysisOnOptionChanged
(
object
sender
,
OptionChangedEventArgs
e
)
{
return
false
;
}
public
Task
NewSolutionSnapshotAsync
(
Solution
solution
,
CancellationToken
cancellationToken
)
{
return
Task
.
CompletedTask
;
}
public
void
RemoveDocument
(
DocumentId
documentId
)
{
}
public
void
RemoveProject
(
ProjectId
projectId
)
{
_cache
.
Remove
(
projectId
);
}
}
}
}
src/VisualStudio/Setup/source.extension.vsixmanifest
浏览文件 @
89358407
...
@@ -35,12 +35,14 @@
...
@@ -35,12 +35,14 @@
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynSnapshot.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynSnapshot.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynCodeAnalysis.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynCodeAnalysis.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteDesignerAttributeService.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteDesignerAttributeService.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteProjectTelemetryService.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteSymbolSearchUpdateEngine.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteSymbolSearchUpdateEngine.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynLanguageServer.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynLanguageServer.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteHost64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteHost64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynSnapshot64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynSnapshot64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynCodeAnalysis64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynCodeAnalysis64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteDesignerAttributeService64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteDesignerAttributeService64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteProjectTelemetryService64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteSymbolSearchUpdateEngine64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteSymbolSearchUpdateEngine64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynLanguageServer64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynLanguageServer64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.VisualStudio.MefComponent"
d:Source=
"Project"
d:ProjectName=
"BasicVisualStudio"
Path=
"|BasicVisualStudio|"
/>
<Asset
Type=
"Microsoft.VisualStudio.MefComponent"
d:Source=
"Project"
d:ProjectName=
"BasicVisualStudio"
Path=
"|BasicVisualStudio|"
/>
...
...
src/Workspaces/Core/Portable/ProjectTelemetry/IProjectTelemetryServiceCallback.cs
0 → 100644
浏览文件 @
89358407
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System.Collections.Generic
;
using
System.Threading
;
using
System.Threading.Tasks
;
namespace
Microsoft.CodeAnalysis.ProjectTelemetry
{
/// <summary>
/// Callback the host (VS) passes to the OOP service to allow it to send batch notifications
/// about telemetry.
/// </summary>
internal
interface
IProjectTelemetryServiceCallback
{
Task
RegisterProjectTelemetryInfoAsync
(
ProjectTelemetryInfo
infos
,
CancellationToken
cancellationToken
);
}
}
src/Workspaces/Core/Portable/ProjectTelemetry/IRemoteProjectTelemetryService.cs
0 → 100644
浏览文件 @
89358407
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System.Threading
;
using
System.Threading.Tasks
;
namespace
Microsoft.CodeAnalysis.ProjectTelemetry
{
/// <summary>
/// Interface to allow host (VS) to inform the OOP service to start incrementally analyzing and
/// reporting results back to the host.
/// </summary>
internal
interface
IRemoteProjectTelemetryService
{
Task
ComputeProjectTelemetryAsync
(
CancellationToken
cancellation
);
}
}
src/Workspaces/Core/Portable/ProjectTelemetry/ProjectTelemetryInfo.cs
0 → 100644
浏览文件 @
89358407
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
namespace
Microsoft.CodeAnalysis.ProjectTelemetry
{
/// <summary>
/// Serialization typed used to pass information to/from OOP and VS.
/// </summary>
internal
struct
ProjectTelemetryInfo
{
public
ProjectId
ProjectId
;
public
string
Language
;
public
int
AnalyzerReferencesCount
;
public
int
ProjectReferencesCount
;
public
int
MetadataReferencesCount
;
public
int
DocumentsCount
;
public
int
AdditionalDocumentsCount
;
public
bool
Equals
(
ProjectTelemetryInfo
other
)
=>
Language
.
Equals
(
other
.
Language
)
&&
AnalyzerReferencesCount
==
other
.
AnalyzerReferencesCount
&&
ProjectReferencesCount
==
other
.
ProjectReferencesCount
&&
MetadataReferencesCount
==
other
.
MetadataReferencesCount
&&
DocumentsCount
==
other
.
DocumentsCount
&&
AdditionalDocumentsCount
==
other
.
AdditionalDocumentsCount
;
}
}
src/Workspaces/Core/Portable/Remote/WellKnownServiceHubServices.cs
浏览文件 @
89358407
...
@@ -13,6 +13,7 @@ public static void Set64bit(bool x64)
...
@@ -13,6 +13,7 @@ public static void Set64bit(bool x64)
SnapshotService
=
"roslynSnapshot"
+
bit
;
SnapshotService
=
"roslynSnapshot"
+
bit
;
CodeAnalysisService
=
"roslynCodeAnalysis"
+
bit
;
CodeAnalysisService
=
"roslynCodeAnalysis"
+
bit
;
RemoteDesignerAttributeService
=
"roslynRemoteDesignerAttributeService"
+
bit
;
RemoteDesignerAttributeService
=
"roslynRemoteDesignerAttributeService"
+
bit
;
RemoteProjectTelemetryService
=
"roslynRemoteProjectTelemetryService"
+
bit
;
RemoteSymbolSearchUpdateEngine
=
"roslynRemoteSymbolSearchUpdateEngine"
+
bit
;
RemoteSymbolSearchUpdateEngine
=
"roslynRemoteSymbolSearchUpdateEngine"
+
bit
;
LanguageServer
=
"roslynLanguageServer"
+
bit
;
LanguageServer
=
"roslynLanguageServer"
+
bit
;
}
}
...
@@ -21,6 +22,7 @@ public static void Set64bit(bool x64)
...
@@ -21,6 +22,7 @@ public static void Set64bit(bool x64)
public
static
string
CodeAnalysisService
{
get
;
private
set
;
}
=
"roslynCodeAnalysis"
;
public
static
string
CodeAnalysisService
{
get
;
private
set
;
}
=
"roslynCodeAnalysis"
;
public
static
string
RemoteSymbolSearchUpdateEngine
{
get
;
private
set
;
}
=
"roslynRemoteSymbolSearchUpdateEngine"
;
public
static
string
RemoteSymbolSearchUpdateEngine
{
get
;
private
set
;
}
=
"roslynRemoteSymbolSearchUpdateEngine"
;
public
static
string
RemoteDesignerAttributeService
{
get
;
private
set
;
}
=
"roslynRemoteDesignerAttributeService"
;
public
static
string
RemoteDesignerAttributeService
{
get
;
private
set
;
}
=
"roslynRemoteDesignerAttributeService"
;
public
static
string
RemoteProjectTelemetryService
{
get
;
private
set
;
}
=
"roslynRemoteProjectTelemetryService"
;
public
static
string
LanguageServer
{
get
;
private
set
;
}
=
"roslynLanguageServer"
;
public
static
string
LanguageServer
{
get
;
private
set
;
}
=
"roslynLanguageServer"
;
// these are OOP implementation itself should care. not features that consume OOP care
// these are OOP implementation itself should care. not features that consume OOP care
...
...
src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryIncrementalAnalyzer.cs
0 → 100644
浏览文件 @
89358407
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System.Collections.Generic
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.ProjectTelemetry
;
using
Microsoft.CodeAnalysis.SolutionCrawler
;
namespace
Microsoft.CodeAnalysis.Remote
{
internal
class
RemoteProjectTelemetryIncrementalAnalyzer
:
IncrementalAnalyzerBase
{
/// <summary>
/// Channel back to VS to inform it of the designer attributes we discover.
/// </summary>
private
readonly
RemoteEndPoint
_endPoint
;
private
readonly
object
_gate
=
new
object
();
private
readonly
Dictionary
<
ProjectId
,
ProjectTelemetryInfo
>
_projectToInfo
=
new
Dictionary
<
ProjectId
,
ProjectTelemetryInfo
>();
public
RemoteProjectTelemetryIncrementalAnalyzer
(
RemoteEndPoint
endPoint
)
=>
_endPoint
=
endPoint
;
/// <summary>
/// Collects data from <paramref name="project"/> and reports it to the telemetry service.
/// </summary>
/// <remarks>
/// Only sends data to the telemetry service when one of the collected data points changes,
/// not necessarily every time this code is called.
/// </remarks>
public
override
async
Task
AnalyzeProjectAsync
(
Project
project
,
bool
semanticsChanged
,
InvocationReasons
reasons
,
CancellationToken
cancellationToken
)
{
if
(!
semanticsChanged
)
return
;
var
projectId
=
project
.
Id
;
var
language
=
project
.
Language
;
var
analyzerReferencesCount
=
project
.
AnalyzerReferences
.
Count
;
var
projectReferencesCount
=
project
.
AllProjectReferences
.
Count
;
var
metadataReferencesCount
=
project
.
MetadataReferences
.
Count
;
var
documentsCount
=
project
.
DocumentIds
.
Count
;
var
additionalDocumentsCount
=
project
.
AdditionalDocumentIds
.
Count
;
var
info
=
new
ProjectTelemetryInfo
{
ProjectId
=
projectId
,
Language
=
language
,
AnalyzerReferencesCount
=
analyzerReferencesCount
,
ProjectReferencesCount
=
projectReferencesCount
,
MetadataReferencesCount
=
metadataReferencesCount
,
DocumentsCount
=
documentsCount
,
AdditionalDocumentsCount
=
additionalDocumentsCount
,
};
lock
(
_gate
)
{
if
(
_projectToInfo
.
TryGetValue
(
projectId
,
out
var
existingInfo
)
&&
existingInfo
.
Equals
(
info
))
{
// already have reported this. No need to notify VS.
return
;
}
_projectToInfo
[
projectId
]
=
info
;
}
await
_endPoint
.
InvokeAsync
(
nameof
(
IProjectTelemetryServiceCallback
.
RegisterProjectTelemetryInfoAsync
),
new
object
[]
{
info
},
cancellationToken
).
ConfigureAwait
(
false
);
}
public
override
void
RemoveProject
(
ProjectId
projectId
)
{
lock
(
_gate
)
{
_projectToInfo
.
Remove
(
projectId
);
}
}
}
}
src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryIncrementalAnalyzerProvider.cs
0 → 100644
浏览文件 @
89358407
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
Microsoft.CodeAnalysis.SolutionCrawler
;
namespace
Microsoft.CodeAnalysis.Remote
{
/// <remarks>Note: this is explicitly <b>not</b> exported. We don't want the <see
/// cref="RemoteWorkspace"/> to automatically load this. Instead, VS waits until it is ready
/// and then calls into OOP to tell it to start analyzing the solution. At that point we'll get
/// created and added to the solution crawler.
/// </remarks>
internal
class
RemoteProjectTelemetryIncrementalAnalyzerProvider
:
IIncrementalAnalyzerProvider
{
private
readonly
RemoteEndPoint
_endPoint
;
public
RemoteProjectTelemetryIncrementalAnalyzerProvider
(
RemoteEndPoint
endPoint
)
{
_endPoint
=
endPoint
;
}
public
IIncrementalAnalyzer
CreateIncrementalAnalyzer
(
Workspace
workspace
)
=>
new
RemoteProjectTelemetryIncrementalAnalyzer
(
_endPoint
);
}
}
src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryService.cs
0 → 100644
浏览文件 @
89358407
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System
;
using
System.IO
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.ProjectTelemetry
;
using
Microsoft.CodeAnalysis.SolutionCrawler
;
namespace
Microsoft.CodeAnalysis.Remote
{
internal
partial
class
RemoteProjectTelemetryService
:
ServiceBase
,
IRemoteProjectTelemetryService
{
public
RemoteProjectTelemetryService
(
Stream
stream
,
IServiceProvider
serviceProvider
)
:
base
(
serviceProvider
,
stream
)
{
StartService
();
}
public
Task
ComputeProjectTelemetryAsync
(
CancellationToken
cancellation
)
{
return
RunServiceAsync
(()
=>
{
var
workspace
=
SolutionService
.
PrimaryWorkspace
;
var
endpoint
=
this
.
EndPoint
;
var
registrationService
=
workspace
.
Services
.
GetRequiredService
<
ISolutionCrawlerRegistrationService
>();
var
analyzerProvider
=
new
RemoteProjectTelemetryIncrementalAnalyzerProvider
(
endpoint
);
registrationService
.
AddAnalyzerProvider
(
analyzerProvider
,
new
IncrementalAnalyzerProviderMetadata
(
nameof
(
RemoteProjectTelemetryIncrementalAnalyzerProvider
),
highPriorityForActiveFile
:
false
,
workspaceKinds
:
WorkspaceKind
.
RemoteWorkspace
));
return
Task
.
CompletedTask
;
},
cancellation
);
}
}
}
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems
浏览文件 @
89358407
...
@@ -318,6 +318,7 @@
...
@@ -318,6 +318,7 @@
<Compile
Include=
"$(MSBuildThisFileDirectory)Utilities\AbstractSpeculationAnalyzer.cs"
/>
<Compile
Include=
"$(MSBuildThisFileDirectory)Utilities\AbstractSpeculationAnalyzer.cs"
/>
<Compile
Include=
"$(MSBuildThisFileDirectory)Utilities\AliasSymbolCache.cs"
/>
<Compile
Include=
"$(MSBuildThisFileDirectory)Utilities\AliasSymbolCache.cs"
/>
<Compile
Include=
"$(MSBuildThisFileDirectory)Utilities\AnnotationTable.cs"
/>
<Compile
Include=
"$(MSBuildThisFileDirectory)Utilities\AnnotationTable.cs"
/>
<Compile
Include=
"$(MSBuildThisFileDirectory)Utilities\AsyncBatchingWorkQueue.cs"
/>
<Compile
Include=
"$(MSBuildThisFileDirectory)Utilities\AsyncLazy`1.cs"
/>
<Compile
Include=
"$(MSBuildThisFileDirectory)Utilities\AsyncLazy`1.cs"
/>
<Compile
Include=
"$(MSBuildThisFileDirectory)Utilities\BidirectionalMap.cs"
/>
<Compile
Include=
"$(MSBuildThisFileDirectory)Utilities\BidirectionalMap.cs"
/>
<Compile
Include=
"$(MSBuildThisFileDirectory)Utilities\BKTree.Builder.cs"
/>
<Compile
Include=
"$(MSBuildThisFileDirectory)Utilities\BKTree.Builder.cs"
/>
...
...
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AsyncBatchingWorkQueue.cs
0 → 100644
浏览文件 @
89358407
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Immutable
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.PooledObjects
;
namespace
Roslyn.Utilities
{
/// <summary>
/// A queue where items can be added to to be processed in batches after some delay has passed.
/// When processing happens, all the items added since the last processing point will be passed
/// along to be worked on. Rounds of processing happen serially, only starting up after a
/// previous round has completed.
/// </summary>
internal
class
AsyncBatchingWorkQueue
<
TItem
>
{
/// <summary>
/// Delay we wait after finishing the processing of one batch and starting up on then.
/// </summary>
private
readonly
TimeSpan
_delay
;
/// <summary>
/// Callback to actually perform the processing of the next batch of work.
/// </summary>
private
readonly
Func
<
ImmutableArray
<
TItem
>,
CancellationToken
,
Task
>
_processBatchAsync
;
private
readonly
CancellationToken
_cancellationToken
;
#
region
protected
by
lock
/// <summary>
/// Lock we will use to ensure the remainder of these fields can be accessed in a threadsafe
/// manner. When work is added we'll place the data into <see cref="_nextBatch"/>.
/// We'll then kick of a task to process this in the future if we don't already have an
/// existing task in flight for that.
/// </summary>
private
readonly
object
_gate
=
new
object
();
/// <summary>
/// Data added that we want to process in our next update task.
/// </summary>
private
readonly
List
<
TItem
>
_nextBatch
=
new
List
<
TItem
>();
/// <summary>
/// Task kicked off to do the next batch of processing of <see cref="_nextBatch"/>. These
/// tasks form a chain so that the next task only processes when the previous one completes.
/// </summary>
private
Task
_updateTask
=
Task
.
CompletedTask
;
/// <summary>
/// Whether or not there is an existing task in flight that will process the current batch
/// of <see cref="_nextBatch"/>. If there is an existing in flight task, we don't need to
/// kick off a new one if we receive more work before it runs.
/// </summary>
private
bool
_taskInFlight
=
false
;
#
endregion
public
AsyncBatchingWorkQueue
(
TimeSpan
delay
,
Func
<
ImmutableArray
<
TItem
>,
CancellationToken
,
Task
>
processBatchAsync
,
CancellationToken
cancellationToken
)
{
_delay
=
delay
;
_processBatchAsync
=
processBatchAsync
;
_cancellationToken
=
cancellationToken
;
}
public
void
AddWork
(
TItem
item
)
{
using
var
_
=
ArrayBuilder
<
TItem
>.
GetInstance
(
out
var
items
);
items
.
Add
(
item
);
AddWork
(
items
);
}
public
void
AddWork
(
IEnumerable
<
TItem
>
items
)
{
// Don't do any more work if we've been asked to shutdown.
if
(
_cancellationToken
.
IsCancellationRequested
)
return
;
lock
(
_gate
)
{
// add our work to the set we'll process in the next batch.
_nextBatch
.
AddRange
(
items
);
if
(!
_taskInFlight
)
{
// No in-flight task. Kick one off to process these messages a second from now.
// We always attach the task to the previous one so that notifications to the ui
// follow the same order as the notification the OOP server sent to us.
_updateTask
=
_updateTask
.
ContinueWithAfterDelayFromAsync
(
_
=>
ProcessNextBatchAsync
(
_cancellationToken
),
_cancellationToken
,
(
int
)
_delay
.
TotalMilliseconds
,
TaskContinuationOptions
.
RunContinuationsAsynchronously
,
TaskScheduler
.
Default
);
_taskInFlight
=
true
;
}
}
}
private
Task
ProcessNextBatchAsync
(
CancellationToken
cancellationToken
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
return
_processBatchAsync
(
GetNextBatchAndResetQueue
(),
_cancellationToken
);
}
private
ImmutableArray
<
TItem
>
GetNextBatchAndResetQueue
()
{
lock
(
_gate
)
{
var
result
=
ArrayBuilder
<
TItem
>.
GetInstance
();
result
.
AddRange
(
_nextBatch
);
// mark there being no existing update task so that the next OOP notification will
// kick one off.
_nextBatch
.
Clear
();
_taskInFlight
=
false
;
return
result
.
ToImmutableAndFree
();
}
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录