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
public static readonly ItemType Folder = new ItemType("Folder"); public static readonly ItemType Folder = new ItemType("Folder");
public static readonly ItemType WebReferences = new ItemType("WebReferences"); 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; readonly string itemName;

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

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

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

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

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

@ -275,11 +275,6 @@ namespace ICSharpCode.SharpDevelop
static ITextBuffer GetParseableFileContentInternal(string fileName) 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); //ITextBuffer res = project.GetParseableFileContent(fileName);
//if (res != null) //if (res != null)
// return res; // return res;

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

@ -5,201 +5,65 @@
// <version>$Revision$</version> // <version>$Revision$</version>
// </file> // </file>
using ICSharpCode.SharpDevelop.Editor;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
using ICSharpCode.SharpDevelop.Dom.Refactoring; using ICSharpCode.SharpDevelop.Dom.Refactoring;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Gui;
namespace ICSharpCode.SharpDevelop.Project namespace ICSharpCode.SharpDevelop.Project
{ {
/// <summary> public class ParseableFileContentEntry
/// 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>>
{ {
void IEnumerator.Reset() { public string FileName { get; private set; }
throw new NotSupportedException(); ITextBuffer openContent;
}
KeyValuePair<string, string> current; public ITextBuffer GetContent()
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)
{ {
isOnMainThread = !WorkbenchSingleton.InvokeRequired; if (openContent != null)
this.projectItems = projectItems; return openContent;
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;
try { try {
fileContent = GetFileContent(item); return new StringTextBuffer(ICSharpCode.AvalonEdit.Utils.FileReader.ReadFileContent(FileName, ParserService.DefaultFileEncoding));
} catch (FileNotFoundException ex) { } catch (IOException) {
LoggingService.Warn("ParseableFileContentEnumerator: " + ex.Message); return null;
return MoveNext(); // skip files that were not found } catch (UnauthorizedAccessException) {
} catch (IOException ex) { return null;
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 GetParseableFileContent(item.Project, fileName);
} }
IList<string> viewContentFileNamesCollection; internal ParseableFileContentEntry(ProjectItem item, IList<string> viewContentFileNamesCollection)
bool IsFileOpen(string fileName)
{ {
if (viewContentFileNamesCollection == null) { this.FileName = item.FileName;
try { foreach (string name in viewContentFileNamesCollection) {
viewContentFileNamesCollection = WorkbenchSingleton.SafeThreadFunction<IList<string>>(FileService.GetOpenFiles); if (FileUtility.IsEqualFileName(name, this.FileName)) {
} catch (InvalidOperationException ex) { openContent = WorkbenchSingleton.SafeThreadFunction(ParserService.GetParseableFileContent, this.FileName);
// can happen if the user closes SharpDevelop while the parser thread is running break;
LoggingService.Warn(ex);
viewContentFileNamesCollection = new string[0];
} }
} }
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; return new ParseableFileContentEntry(p, viewContentFileNamesCollection);
if (p == null) return null;
IDocument document = p.GetDocumentForFile(file);
if (document == null) return null;
return document.Text;
} }
} }
} }

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

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

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

@ -113,19 +113,6 @@ namespace ICSharpCode.SharpDevelop.Gui
listBox.ScrollIntoView(listBox.Items[index]); 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>(); Dictionary<string, object> visibleEntries = new Dictionary<string, object>();
int bestMatchType; int bestMatchType;
double bestPriority; double bestPriority;
@ -164,29 +151,6 @@ namespace ICSharpCode.SharpDevelop.Gui
if (!int.TryParse(line, out lineNr)) if (!int.TryParse(line, out lineNr))
lineNr = 0; lineNr = 0;
AddSourceFiles(file, lineNr); 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 { } else {
AddSourceFiles(text, 0); AddSourceFiles(text, 0);
foreach (IClass c in SearchClasses(text)) { foreach (IClass c in SearchClasses(text)) {

Loading…
Cancel
Save