Browse Source

LoadSolutionProjectsThread: use multiple processor cores for parsing

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4811 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 16 years ago
parent
commit
d7cd3faf36
  1. 5
      src/Main/Base/Project/Src/Project/Items/ItemType.cs
  2. 2
      src/Main/Base/Project/Src/Services/File/FileService.cs
  3. 24
      src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs
  4. 5
      src/Main/Base/Project/Src/Services/ParserService/ParserService.cs
  5. 204
      src/Main/Base/Project/Src/Services/ProjectService/ParseableFileContentEnumerator.cs
  6. 16
      src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs
  7. 36
      src/Main/Base/Project/Src/TextEditor/Gui/Dialogs/GotoDialog.cs

5
src/Main/Base/Project/Src/Project/Items/ItemType.cs

@ -56,6 +56,11 @@ namespace ICSharpCode.SharpDevelop.Project @@ -56,6 +56,11 @@ namespace ICSharpCode.SharpDevelop.Project
public static readonly ItemType Folder = new ItemType("Folder");
public static readonly ItemType WebReferences = new ItemType("WebReferences");
/// <summary>
/// Gets a collection of item types that are known not to be used for files.
/// </summary>
public static readonly ReadOnlyCollectionWrapper<ItemType> NonFileItemTypes
= new ReadOnlyCollectionWrapper<ItemType>(new List<ItemType>(ReferenceItemTypes) { Folder, WebReferences, Import });
readonly string itemName;

2
src/Main/Base/Project/Src/Services/File/FileService.cs

@ -81,6 +81,8 @@ namespace ICSharpCode.SharpDevelop @@ -81,6 +81,8 @@ namespace ICSharpCode.SharpDevelop
if (fileName == null)
throw new ArgumentNullException("fileName");
WorkbenchSingleton.AssertMainThread();
fileName = FileUtility.NormalizePath(fileName);
OpenedFile file;
openedFileDict.TryGetValue(fileName, out file);

24
src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs

@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Dom;
@ -246,7 +247,6 @@ namespace ICSharpCode.SharpDevelop @@ -246,7 +247,6 @@ namespace ICSharpCode.SharpDevelop
{
if (!initializing) return;
//int progressStart = progressMonitor.WorkDone;
ParseableFileContentEnumerator enumerator = new ParseableFileContentEnumerator(project);
try {
IProjectContent[] referencedContents;
lock (this.ReferencedContents) {
@ -260,21 +260,21 @@ namespace ICSharpCode.SharpDevelop @@ -260,21 +260,21 @@ namespace ICSharpCode.SharpDevelop
}
}
while (enumerator.MoveNext()) {
int i = enumerator.Index;
if ((i % 4) == 2) {
//progressMonitor.WorkDone = progressStart + i;
token.ThrowIfCancellationRequested();
ParseableFileContentFinder finder = new ParseableFileContentFinder();
var fileContents =
from p in project.Items.AsParallel().WithCancellation(token)
where !ItemType.NonFileItemTypes.Contains(p.ItemType)
select finder.Create(p);
fileContents.ForAll(
entry => {
ITextBuffer content = entry.GetContent();
if (content != null)
ParserService.ParseFile(this, entry.FileName, content);
}
ParserService.ParseFile(this, enumerator.CurrentFileName, new StringTextBuffer(enumerator.CurrentFileContent));
if (!initializing) return;
}
);
} finally {
initializing = false;
//progressMonitor.WorkDone = progressStart + enumerator.ItemCount;
enumerator.Dispose();
}
}

5
src/Main/Base/Project/Src/Services/ParserService/ParserService.cs

@ -275,11 +275,6 @@ namespace ICSharpCode.SharpDevelop @@ -275,11 +275,6 @@ namespace ICSharpCode.SharpDevelop
static ITextBuffer GetParseableFileContentInternal(string fileName)
{
IViewContent viewContent = FileService.GetOpenFile(fileName);
IEditable editable = viewContent as IEditable;
if (editable != null) {
return editable.CreateSnapshot();
}
//ITextBuffer res = project.GetParseableFileContent(fileName);
//if (res != null)
// return res;

204
src/Main/Base/Project/Src/Services/ProjectService/ParseableFileContentEnumerator.cs

@ -5,201 +5,65 @@ @@ -5,201 +5,65 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Editor;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
using ICSharpCode.SharpDevelop.Dom.Refactoring;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui;
namespace ICSharpCode.SharpDevelop.Project
{
/// <summary>
/// An enumerator which enumerates through a list of project items, returning the
/// parseable file content of each item.
/// </summary>
/// <remarks>
/// This class is thread-safe in a very limited way:
/// It can be created from every thread, but may be only used by the thread that created it.
/// It automatically uses WorkbenchSingleton.SafeThreadCall for reading currently open
/// files when it is created/accessed from a thread.
/// </remarks>
public class ParseableFileContentEnumerator : IEnumerator<KeyValuePair<string, string>>
public class ParseableFileContentEntry
{
void IEnumerator.Reset() {
throw new NotSupportedException();
}
public string FileName { get; private set; }
ITextBuffer openContent;
KeyValuePair<string, string> current;
object IEnumerator.Current {
get {
return current;
}
}
public KeyValuePair<string, string> Current {
get {
return current;
}
}
public string CurrentFileName {
get {
return current.Key;
}
}
public string CurrentFileContent {
get {
return current.Value;
}
}
public void Dispose()
{
}
IList<ProjectItem> projectItems;
bool isOnMainThread;
Encoding defaultEncoding;
public ParseableFileContentEnumerator(IProject project) : this(project.Items) { }
public ParseableFileContentEnumerator(IList<ProjectItem> projectItems)
public ITextBuffer GetContent()
{
isOnMainThread = !WorkbenchSingleton.InvokeRequired;
this.projectItems = projectItems;
if (projectItems.Count > 0) {
nextItem = projectItems[0];
}
defaultEncoding = ParserService.DefaultFileEncoding;
}
string GetParseableFileContent(IProject project, string fileName)
{
// Loading the source files is done asynchronously:
// While one file is parsed, the next is already loaded from disk.
// Load file from memory if it is open
OpenedFile file = FileService.GetOpenedFile(fileName);
if (file != null) {
string content;
if (isOnMainThread) {
content = GetFileContentFromFileDocumentProvider(file);
} else {
content = WorkbenchSingleton.SafeThreadFunction<OpenedFile, string>(GetFileContentFromFileDocumentProvider, file);
}
if (content != null) {
return content;
}
using(Stream s = file.OpenRead()) {
Encoding encoding = defaultEncoding;
return ICSharpCode.TextEditor.Util.FileReader.ReadFileContent(s, ref encoding);
}
}
// load file
return ICSharpCode.TextEditor.Util.FileReader.ReadFileContent(fileName, defaultEncoding);
}
ProjectItem nextItem;
int index = 0;
public int ItemCount {
get {
return projectItems.Count;
}
}
public int Index {
get {
return index;
}
}
public bool MoveNext()
{
ProjectItem item = nextItem;
nextItem = (++index < projectItems.Count) ? projectItems[index] : null;
if (item == null) return false;
if (ParserService.CreateParser(item.FileName) == null)
return MoveNext();
string fileContent;
if (openContent != null)
return openContent;
try {
fileContent = GetFileContent(item);
} catch (FileNotFoundException ex) {
LoggingService.Warn("ParseableFileContentEnumerator: " + ex.Message);
return MoveNext(); // skip files that were not found
} catch (IOException ex) {
LoggingService.Warn("ParseableFileContentEnumerator: " + ex.Message);
return MoveNext(); // skip invalid files
}
current = new KeyValuePair<string, string>(item.FileName, fileContent);
return true;
}
string GetFileContent(ProjectItem item)
{
string fileName = item.FileName;
if (IsFileOpen(fileName)) {
string content;
if (isOnMainThread)
content = GetFileContentFromOpenFile(fileName);
else
content = WorkbenchSingleton.SafeThreadFunction<string, string>(GetFileContentFromOpenFile, fileName);
if (content != null)
return content;
return new StringTextBuffer(ICSharpCode.AvalonEdit.Utils.FileReader.ReadFileContent(FileName, ParserService.DefaultFileEncoding));
} catch (IOException) {
return null;
} catch (UnauthorizedAccessException) {
return null;
}
return GetParseableFileContent(item.Project, fileName);
}
IList<string> viewContentFileNamesCollection;
bool IsFileOpen(string fileName)
internal ParseableFileContentEntry(ProjectItem item, IList<string> viewContentFileNamesCollection)
{
if (viewContentFileNamesCollection == null) {
try {
viewContentFileNamesCollection = WorkbenchSingleton.SafeThreadFunction<IList<string>>(FileService.GetOpenFiles);
} catch (InvalidOperationException ex) {
// can happen if the user closes SharpDevelop while the parser thread is running
LoggingService.Warn(ex);
viewContentFileNamesCollection = new string[0];
this.FileName = item.FileName;
foreach (string name in viewContentFileNamesCollection) {
if (FileUtility.IsEqualFileName(name, this.FileName)) {
openContent = WorkbenchSingleton.SafeThreadFunction(ParserService.GetParseableFileContent, this.FileName);
break;
}
}
foreach (string contentName in viewContentFileNamesCollection) {
if (contentName != null) {
if (FileUtility.IsEqualFileName(fileName, contentName))
return true;
}
}
return false;
}
string GetFileContentFromOpenFile(string fileName)
{
IViewContent viewContent = FileService.GetOpenFile(fileName);
IEditable editable = viewContent as IEditable;
if (editable != null) {
return editable.Text;
}
return null;
}
}
/// <summary>
/// Can be used to create ParseableFileContentEntry for ProjectItems.
/// This class is thread-safe.
/// </summary>
public class ParseableFileContentFinder
{
IList<string> viewContentFileNamesCollection = WorkbenchSingleton.SafeThreadFunction(FileService.GetOpenFiles);
static string GetFileContentFromFileDocumentProvider(OpenedFile file)
/// <summary>
/// Retrieves the file contents for the specified project items.
/// </summary>
public ParseableFileContentEntry Create(ProjectItem p)
{
IFileDocumentProvider p = file.CurrentView as IFileDocumentProvider;
if (p == null) return null;
IDocument document = p.GetDocumentForFile(file);
if (document == null) return null;
return document.Text;
return new ParseableFileContentEntry(p, viewContentFileNamesCollection);
}
}
}

16
src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs

@ -152,7 +152,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -152,7 +152,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
ownerClass = ownerClass.GetCompoundClass();
files = GetPossibleFiles(ownerClass, member);
}
ParseableFileContentEnumerator enumerator = new ParseableFileContentEnumerator(files.ToArray());
ParseableFileContentFinder finder = new ParseableFileContentFinder();
List<Reference> references = new List<Reference>();
try {
if (progressMonitor != null) {
@ -163,21 +163,27 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -163,21 +163,27 @@ namespace ICSharpCode.SharpDevelop.Refactoring
System.Diagnostics.Debugger.Break();
}
#endif
while (enumerator.MoveNext()) {
int index = 0;
foreach (ProjectItem item in files) {
var entry = finder.Create(item);
if (progressMonitor != null) {
progressMonitor.WorkDone = enumerator.Index;
progressMonitor.WorkDone = index;
if (progressMonitor.IsCancelled) {
return null;
}
}
AddReferences(references, ownerClass, member, isLocal, enumerator.CurrentFileName, enumerator.CurrentFileContent);
ITextBuffer content = entry.GetContent();
if (content != null) {
AddReferences(references, ownerClass, member, isLocal, entry.FileName, content.Text);
}
index++;
}
} finally {
if (progressMonitor != null) {
progressMonitor.Done();
}
enumerator.Dispose();
}
return references;
}

36
src/Main/Base/Project/Src/TextEditor/Gui/Dialogs/GotoDialog.cs

@ -113,19 +113,6 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -113,19 +113,6 @@ namespace ICSharpCode.SharpDevelop.Gui
listBox.ScrollIntoView(listBox.Items[index]);
}
static readonly IList<ICompletionItem> emptyList = new ICompletionItem[0];
IList<ICompletionItem> Resolve(string expression)
{
ITextEditor editor = GetEditor();
if (editor != null) {
CodeCompletionItemProvider cdp = new DotCodeCompletionItemProvider();
var list = cdp.GenerateCompletionListForExpression(editor, new ExpressionResult(expression));
return list != null ? list.Items.ToList() : emptyList;
}
return emptyList;
}
Dictionary<string, object> visibleEntries = new Dictionary<string, object>();
int bestMatchType;
double bestPriority;
@ -164,29 +151,6 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -164,29 +151,6 @@ namespace ICSharpCode.SharpDevelop.Gui
if (!int.TryParse(line, out lineNr))
lineNr = 0;
AddSourceFiles(file, lineNr);
} else if (dotPos > 0) {
AddSourceFiles(text, 0);
string expression = text.Substring(0, dotPos).Trim();
text = text.Substring(dotPos + 1).Trim();
ShowCompletionData(Resolve(expression), text);
foreach (IClass c in SearchClasses(expression)) {
if (c.Name.Equals(expression, StringComparison.InvariantCultureIgnoreCase)) {
foreach (IMethod m in c.DefaultReturnType.GetMethods()) {
if (!m.IsConstructor) {
AddItemIfMatchText(text, m, ClassBrowserIconService.GetIcon(m));
}
}
foreach (IField f in c.DefaultReturnType.GetFields()) {
AddItemIfMatchText(text, f, ClassBrowserIconService.GetIcon(f));
}
foreach (IProperty p in c.DefaultReturnType.GetProperties()) {
AddItemIfMatchText(text, p, ClassBrowserIconService.GetIcon(p));
}
foreach (IEvent evt in c.DefaultReturnType.GetEvents()) {
AddItemIfMatchText(text, evt, ClassBrowserIconService.GetIcon(evt));
}
}
}
} else {
AddSourceFiles(text, 0);
foreach (IClass c in SearchClasses(text)) {

Loading…
Cancel
Save