From 44427073fe83ffcd660520862c2e04429a75178a Mon Sep 17 00:00:00 2001 From: ronzulu <75528127+ronzulu@users.noreply.github.com> Date: Fri, 29 Mar 2024 22:14:41 +1100 Subject: [PATCH 1/7] Possibly fixed, for beta testing --- src/NoteFileLoader.ts | 6 ++++++ src/NoteQuestionParser.ts | 22 ++++++++++++++++------ src/SRFile.ts | 9 ++++++++- src/main.ts | 15 +++++++++++++++ tests/unit/helpers/UnitTestHelper.ts | 6 ------ tests/unit/helpers/UnitTestSRFile.ts | 4 ++++ 6 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/NoteFileLoader.ts b/src/NoteFileLoader.ts index 252e863b..89720d91 100644 --- a/src/NoteFileLoader.ts +++ b/src/NoteFileLoader.ts @@ -11,6 +11,11 @@ export class NoteFileLoader { noteTopicPath: TopicPath; noteFile: ISRFile; settings: SRSettings; + private _hasTopicPaths: boolean; + + public get hasTopicPaths(): boolean { + return this._hasTopicPaths; + } constructor(settings: SRSettings) { this.settings = settings; @@ -27,6 +32,7 @@ export class NoteFileLoader { folderTopicPath, onlyKeepQuestionsWithTopicPath, ); + this._hasTopicPaths = questionParser.hasTopicPaths; const result: Note = new Note(noteFile, questionList); return result; diff --git a/src/NoteQuestionParser.ts b/src/NoteQuestionParser.ts index f5f197c5..505b4205 100644 --- a/src/NoteQuestionParser.ts +++ b/src/NoteQuestionParser.ts @@ -19,6 +19,11 @@ export class NoteQuestionParser { frontmatterTopicPathList: TopicPathList; contentTopicPathInfo: TopicPathList[]; questionList: Question[]; + private _hasTopicPaths: boolean; + + public get hasTopicPaths(): boolean { + return this._hasTopicPaths; + } constructor(settings: SRSettings) { this.settings = settings; @@ -32,13 +37,18 @@ export class NoteQuestionParser { this.noteFile = noteFile; const noteText: string = await noteFile.read(); - // Get the list of tags, and analyse for the topic list - const tagCacheList: TagCache[] = noteFile.getAllTagsFromText(); - - const hasTopicPaths = - tagCacheList.some((item) => SettingsUtil.isFlashcardTag(this.settings, item.tag)) || + // For efficiency, we first get the tag list from the Obsidian cache + // (this only gives the tag names, not the line numbers, but this is sufficient for this first step) + const tagList: string[] = noteFile.getAllTagsFromCache(); + this._hasTopicPaths = + tagList.some((item) => SettingsUtil.isFlashcardTag(this.settings, item)) || folderTopicPath.hasPath; - if (hasTopicPaths) { + + if (this._hasTopicPaths) { + // Now that we know there are relevant flashcard tags in the file, we can get the more detailed info + // that includes the line numbers of each tag + const tagCacheList: TagCache[] = noteFile.getAllTagsFromText(); + // The following analysis can require fair computation. // There is no point doing it if there aren't any topic paths diff --git a/src/SRFile.ts b/src/SRFile.ts index bc18b10a..6df06ae7 100644 --- a/src/SRFile.ts +++ b/src/SRFile.ts @@ -1,9 +1,11 @@ -import { MetadataCache, TFile, Vault, HeadingCache, TagCache, FrontMatterCache } from "obsidian"; +import { MetadataCache, TFile, Vault, HeadingCache, getAllTags as ObsidianGetAllTags, + TagCache, FrontMatterCache } from "obsidian"; import { parseObsidianFrontmatterTag } from "./util/utils"; export interface ISRFile { get path(): string; get basename(): string; + getAllTagsFromCache(): string[]; getAllTagsFromText(): TagCache[]; getQuestionContext(cardLine: number): string[]; read(): Promise; @@ -29,6 +31,11 @@ export class SrTFile implements ISRFile { return this.file.basename; } + getAllTagsFromCache(): string[] { + const fileCachedData = this.metadataCache.getFileCache(this.file) || {}; + return ObsidianGetAllTags(fileCachedData) || []; + } + getAllTagsFromText(): TagCache[] { const result: TagCache[] = [] as TagCache[]; const fileCachedData = this.metadataCache.getFileCache(this.file) || {}; diff --git a/src/main.ts b/src/main.ts index a8c3c278..44af3984 100644 --- a/src/main.ts +++ b/src/main.ts @@ -88,9 +88,13 @@ export default class SRPlugin extends Plugin { public deckTree: Deck = new Deck("root", null); private remainingDeckTree: Deck; public cardStats: Stats; + private withFlashcardTagCount: number; + private hasChangedCount: number; + private withFlashcardCount: number; async onload(): Promise { await this.loadPluginData(); + console.log(`OSR: onload: bug-914-slow-load: v2`); this.easeByPath = new NoteEaseList(this.data.settings); this.questionPostponementList = new QuestionPostponementList( this, @@ -349,6 +353,11 @@ export default class SRPlugin extends Plugin { } async sync(): Promise { + let markdownCount: number = 0; + this.withFlashcardTagCount = 0; + this.withFlashcardCount = 0; + this.hasChangedCount = 0; + if (this.syncLock) { return; } @@ -377,6 +386,8 @@ export default class SRPlugin extends Plugin { const notes: TFile[] = this.app.vault.getMarkdownFiles(); for (const noteFile of notes) { + markdownCount++; + if ( this.data.settings.noteFoldersToIgnore.some((folder) => noteFile.path.startsWith(folder), @@ -492,6 +503,7 @@ export default class SRPlugin extends Plugin { if (this.data.settings.showDebugMessages) { console.log(`SR: ${t("EASES")}`, this.easeByPath.dict); console.log(`SR: ${t("DECKS")}`, this.deckTree); + console.log(`sync: markdownCount: ${markdownCount}, withFlashcardTagCount: ${this.withFlashcardTagCount}, withFlashcardCount: ${this.withFlashcardCount}, hasChangedCount: ${this.hasChangedCount}`); } if (this.data.settings.showDebugMessages) { @@ -555,7 +567,10 @@ export default class SRPlugin extends Plugin { ); const note: Note = await loader.load(this.createSrTFile(noteFile), folderTopicPath); + if (loader.hasTopicPaths) this.withFlashcardTagCount++; + if (note.questionList.length > 0) this.withFlashcardCount++; if (note.hasChanged) { + this.hasChangedCount++; note.writeNoteFile(this.data.settings); } return note; diff --git a/tests/unit/helpers/UnitTestHelper.ts b/tests/unit/helpers/UnitTestHelper.ts index e87c8420..b5a60021 100644 --- a/tests/unit/helpers/UnitTestHelper.ts +++ b/tests/unit/helpers/UnitTestHelper.ts @@ -56,9 +56,3 @@ export function unitTest_GetAllTagsFromTextEx(text: string): TagCache[] { return result; } -export function unitTest_GetAllTagsFromText(text: string): string[] { - const tagRegex = /#[^\s#]+/gi; - const result: RegExpMatchArray = text.match(tagRegex); - if (!result) return []; - return result; -} diff --git a/tests/unit/helpers/UnitTestSRFile.ts b/tests/unit/helpers/UnitTestSRFile.ts index 3110f892..4878ca82 100644 --- a/tests/unit/helpers/UnitTestSRFile.ts +++ b/tests/unit/helpers/UnitTestSRFile.ts @@ -19,6 +19,10 @@ export class UnitTestSRFile implements ISRFile { return ""; } + getAllTagsFromCache(): string[] { + return unitTest_GetAllTagsFromTextEx(this.content).map((item) => item.tag); + } + getAllTagsFromText(): TagCache[] { return unitTest_GetAllTagsFromTextEx(this.content); } From 020b2397b2115b94bafa70d3127eff6a2acd716f Mon Sep 17 00:00:00 2001 From: ronzulu <75528127+ronzulu@users.noreply.github.com> Date: Thu, 4 Apr 2024 22:18:03 +1100 Subject: [PATCH 2/7] Added logging of detailed timing debug --- src/NoteQuestionParser.ts | 4 ++++ src/main.ts | 19 ++++++++++++++++++- src/util/DateProvider.ts | 26 ++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/NoteQuestionParser.ts b/src/NoteQuestionParser.ts index 505b4205..843dec79 100644 --- a/src/NoteQuestionParser.ts +++ b/src/NoteQuestionParser.ts @@ -8,6 +8,7 @@ import { SRSettings, SettingsUtil } from "./settings"; import { ISRFile } from "./SRFile"; import { TopicPath, TopicPathList } from "./TopicPath"; import { extractFrontmatter, splitTextIntoLineArray } from "./util/utils"; +import { testTimeLog } from "./util/DateProvider"; export class NoteQuestionParser { settings: SRSettings; @@ -43,11 +44,13 @@ export class NoteQuestionParser { this._hasTopicPaths = tagList.some((item) => SettingsUtil.isFlashcardTag(this.settings, item)) || folderTopicPath.hasPath; + testTimeLog("cql.A"); if (this._hasTopicPaths) { // Now that we know there are relevant flashcard tags in the file, we can get the more detailed info // that includes the line numbers of each tag const tagCacheList: TagCache[] = noteFile.getAllTagsFromText(); + testTimeLog("cql.B"); // The following analysis can require fair computation. // There is no point doing it if there aren't any topic paths @@ -73,6 +76,7 @@ export class NoteQuestionParser { } else { this.questionList = [] as Question[]; } + testTimeLog("cql.C"); return this.questionList; } diff --git a/src/main.ts b/src/main.ts index 44af3984..a665834d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -41,6 +41,7 @@ import { NoteEaseCalculator } from "./NoteEaseCalculator"; import { DeckTreeStatsCalculator } from "./DeckTreeStatsCalculator"; import { NoteEaseList } from "./NoteEaseList"; import { QuestionPostponementList } from "./QuestionPostponementList"; +import { testTimeFormatLapInfo, testTimeGetLapTime, testTimeLog, testTimeStart } from "./util/DateProvider"; interface PluginData { settings: SRSettings; @@ -94,7 +95,7 @@ export default class SRPlugin extends Plugin { async onload(): Promise { await this.loadPluginData(); - console.log(`OSR: onload: bug-914-slow-load: v2`); + console.log(`OSR: onload: bug-914-slow-load: B`); this.easeByPath = new NoteEaseList(this.data.settings); this.questionPostponementList = new QuestionPostponementList( this, @@ -384,8 +385,16 @@ export default class SRPlugin extends Plugin { await this.savePluginData(); } + testTimeStart(); + let totalLapTime: number = 0; + let info: string = ""; const notes: TFile[] = this.app.vault.getMarkdownFiles(); for (const noteFile of notes) { + if (markdownCount != 0) { + info += `sync:\t${markdownCount}\t${testTimeFormatLapInfo()}\t`; + totalLapTime += testTimeGetLapTime(); + } + testTimeStart(); markdownCount++; if ( @@ -417,6 +426,7 @@ export default class SRPlugin extends Plugin { } const note: Note = await this.loadNote(noteFile); + testTimeLog("sync.A"); if (note.questionList.length > 0) { const flashcardsInNoteAvgEase: number = NoteEaseCalculator.Calculate( note, @@ -447,6 +457,7 @@ export default class SRPlugin extends Plugin { break; } } + testTimeLog("sync.B"); if (shouldIgnore) { continue; } @@ -482,6 +493,12 @@ export default class SRPlugin extends Plugin { this.reviewDecks[matchedNoteTag].scheduledNotes.push({ note: noteFile, dueUnix }); } } + if (markdownCount != 0) { + info += `sync:\t${markdownCount}\t${testTimeFormatLapInfo()}\t`; + totalLapTime += testTimeGetLapTime(); + } + console.log(`sync:\t${info}`); + console.log(`sync:\tTotalLapTime\t${totalLapTime}`); graph.rank(0.85, 0.000001, (node: string, rank: number) => { this.pageranks[node] = rank * 10000; diff --git a/src/util/DateProvider.ts b/src/util/DateProvider.ts index b995818d..64d1342c 100644 --- a/src/util/DateProvider.ts +++ b/src/util/DateProvider.ts @@ -2,6 +2,32 @@ import moment from "moment"; import { Moment } from "moment"; import { ALLOWED_DATE_FORMATS } from "src/constants"; +var testTimeInfo: [ string, number ][]; + +export function testTimeStart(): void { + testTimeInfo = [ [ "Start", moment().valueOf() ] ]; +} + +export function testTimeLog(desc: string): void { + testTimeInfo.push([ desc, moment().valueOf() ]); +} + +export function testTimeGetLapTime(): number { + return moment().valueOf() - testTimeInfo[0][1]; +} + +export function testTimeFormatLapInfo(): string { + let prevTime: number = testTimeInfo[0][1]; + let result: string = ""; + for (let i = 1; i < testTimeInfo.length; i++) { + const thisTime: number = testTimeInfo[i][1]; + result += `\t${testTimeInfo[i][0]}\t${thisTime - prevTime}`; + prevTime = thisTime; + } + result += `\tLapTime\t${testTimeGetLapTime()}|`; + return result; +} + export interface IDateProvider { get today(): Moment; } From a85744101003918ed2bbdc50d9361e728e8859a7 Mon Sep 17 00:00:00 2001 From: ronzulu <75528127+ronzulu@users.noreply.github.com> Date: Mon, 8 Apr 2024 08:39:45 +1000 Subject: [PATCH 3/7] Problem fixed, still needs tidy up --- src/NoteQuestionParser.ts | 11 +++++++---- src/SRFile.ts | 7 ++++++- src/main.ts | 9 ++++++--- src/util/DateProvider.ts | 26 -------------------------- src/util/TimeTestUtil.ts | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 34 deletions(-) create mode 100644 src/util/TimeTestUtil.ts diff --git a/src/NoteQuestionParser.ts b/src/NoteQuestionParser.ts index 843dec79..cf61d332 100644 --- a/src/NoteQuestionParser.ts +++ b/src/NoteQuestionParser.ts @@ -36,8 +36,6 @@ export class NoteQuestionParser { onlyKeepQuestionsWithTopicPath: boolean, ): Promise { this.noteFile = noteFile; - const noteText: string = await noteFile.read(); - // For efficiency, we first get the tag list from the Obsidian cache // (this only gives the tag names, not the line numbers, but this is sufficient for this first step) const tagList: string[] = noteFile.getAllTagsFromCache(); @@ -47,10 +45,13 @@ export class NoteQuestionParser { testTimeLog("cql.A"); if (this._hasTopicPaths) { + const noteText: string = await noteFile.read(); + + testTimeLog(`cql.B\t${noteText.length}`); // Now that we know there are relevant flashcard tags in the file, we can get the more detailed info // that includes the line numbers of each tag const tagCacheList: TagCache[] = noteFile.getAllTagsFromText(); - testTimeLog("cql.B"); + testTimeLog("cql.C1"); // The following analysis can require fair computation. // There is no point doing it if there aren't any topic paths @@ -74,9 +75,11 @@ export class NoteQuestionParser { this.questionList = this.questionList.filter((q) => q.topicPathList); } } else { + testTimeLog("cql.B"); + testTimeLog("cql.C2"); this.questionList = [] as Question[]; } - testTimeLog("cql.C"); + testTimeLog("cql.D"); return this.questionList; } diff --git a/src/SRFile.ts b/src/SRFile.ts index 6df06ae7..3cfcc287 100644 --- a/src/SRFile.ts +++ b/src/SRFile.ts @@ -1,6 +1,7 @@ import { MetadataCache, TFile, Vault, HeadingCache, getAllTags as ObsidianGetAllTags, TagCache, FrontMatterCache } from "obsidian"; import { parseObsidianFrontmatterTag } from "./util/utils"; +import { testTimeLog } from "./util/DateProvider"; export interface ISRFile { get path(): string; @@ -32,8 +33,12 @@ export class SrTFile implements ISRFile { } getAllTagsFromCache(): string[] { + testTimeLog("gatfc.A"); const fileCachedData = this.metadataCache.getFileCache(this.file) || {}; - return ObsidianGetAllTags(fileCachedData) || []; + testTimeLog("gatfc.B"); + const result: string[] = ObsidianGetAllTags(fileCachedData) || []; + testTimeLog("gatfc.C"); + return result; } getAllTagsFromText(): TagCache[] { diff --git a/src/main.ts b/src/main.ts index a665834d..deb85c46 100644 --- a/src/main.ts +++ b/src/main.ts @@ -95,7 +95,7 @@ export default class SRPlugin extends Plugin { async onload(): Promise { await this.loadPluginData(); - console.log(`OSR: onload: bug-914-slow-load: B`); + console.log(`OSR: onload: bug-914-slow-load: D`); this.easeByPath = new NoteEaseList(this.data.settings); this.questionPostponementList = new QuestionPostponementList( this, @@ -517,13 +517,13 @@ export default class SRPlugin extends Plugin { const calc: DeckTreeStatsCalculator = new DeckTreeStatsCalculator(); this.cardStats = calc.calculate(this.deckTree); + console.log(`sync: markdownCount: ${markdownCount}, withFlashcardTagCount: ${this.withFlashcardTagCount}, withFlashcardCount: ${this.withFlashcardCount}, hasChangedCount: ${this.hasChangedCount}`); if (this.data.settings.showDebugMessages) { console.log(`SR: ${t("EASES")}`, this.easeByPath.dict); console.log(`SR: ${t("DECKS")}`, this.deckTree); - console.log(`sync: markdownCount: ${markdownCount}, withFlashcardTagCount: ${this.withFlashcardTagCount}, withFlashcardCount: ${this.withFlashcardCount}, hasChangedCount: ${this.hasChangedCount}`); } - if (this.data.settings.showDebugMessages) { + if (this.data.settings.showDebugMessages || true) { console.log( "SR: " + t("SYNC_TIME_TAKEN", { @@ -576,12 +576,14 @@ export default class SRPlugin extends Plugin { } async loadNote(noteFile: TFile): Promise { + testTimeLog("ln.A"); const loader: NoteFileLoader = new NoteFileLoader(this.data.settings); const srFile: ISRFile = this.createSrTFile(noteFile); const folderTopicPath: TopicPath = TopicPath.getFolderPathFromFilename( srFile, this.data.settings, ); + testTimeLog("ln.B"); const note: Note = await loader.load(this.createSrTFile(noteFile), folderTopicPath); if (loader.hasTopicPaths) this.withFlashcardTagCount++; @@ -590,6 +592,7 @@ export default class SRPlugin extends Plugin { this.hasChangedCount++; note.writeNoteFile(this.data.settings); } + testTimeLog("ln.C"); return note; } diff --git a/src/util/DateProvider.ts b/src/util/DateProvider.ts index 64d1342c..b995818d 100644 --- a/src/util/DateProvider.ts +++ b/src/util/DateProvider.ts @@ -2,32 +2,6 @@ import moment from "moment"; import { Moment } from "moment"; import { ALLOWED_DATE_FORMATS } from "src/constants"; -var testTimeInfo: [ string, number ][]; - -export function testTimeStart(): void { - testTimeInfo = [ [ "Start", moment().valueOf() ] ]; -} - -export function testTimeLog(desc: string): void { - testTimeInfo.push([ desc, moment().valueOf() ]); -} - -export function testTimeGetLapTime(): number { - return moment().valueOf() - testTimeInfo[0][1]; -} - -export function testTimeFormatLapInfo(): string { - let prevTime: number = testTimeInfo[0][1]; - let result: string = ""; - for (let i = 1; i < testTimeInfo.length; i++) { - const thisTime: number = testTimeInfo[i][1]; - result += `\t${testTimeInfo[i][0]}\t${thisTime - prevTime}`; - prevTime = thisTime; - } - result += `\tLapTime\t${testTimeGetLapTime()}|`; - return result; -} - export interface IDateProvider { get today(): Moment; } diff --git a/src/util/TimeTestUtil.ts b/src/util/TimeTestUtil.ts new file mode 100644 index 00000000..8017032f --- /dev/null +++ b/src/util/TimeTestUtil.ts @@ -0,0 +1,32 @@ +import moment from "moment"; + +// These functions were used to diagnose performance issue +// https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/914 + +var testTimeInfo: [ string, number ][]; + +export function testTimeStart(): void { + testTimeInfo = [ [ "Start", moment().valueOf() ] ]; +} + +export function testTimeLog(desc: string): void { + if (testTimeInfo == null) testTimeStart(); + testTimeInfo.push([ desc, moment().valueOf() ]); +} + +export function testTimeGetLapTime(): number { + return moment().valueOf() - testTimeInfo[0][1]; +} + +export function testTimeFormatLapInfo(): string { + let prevTime: number = testTimeInfo[0][1]; + let result: string = ""; + for (let i = 1; i < testTimeInfo.length; i++) { + const thisTime: number = testTimeInfo[i][1]; + result += `\t${testTimeInfo[i][0]}\t${thisTime - prevTime}`; + prevTime = thisTime; + } + result += `\tLapTime\t${testTimeGetLapTime()}|`; + return result; +} + From b9ef10092ca8a60914798d1c71b050d4628765bd Mon Sep 17 00:00:00 2001 From: ronzulu <75528127+ronzulu@users.noreply.github.com> Date: Mon, 8 Apr 2024 08:53:46 +1000 Subject: [PATCH 4/7] Removed detailed timing logging --- src/NoteQuestionParser.ts | 7 ------- src/main.ts | 36 +----------------------------------- 2 files changed, 1 insertion(+), 42 deletions(-) diff --git a/src/NoteQuestionParser.ts b/src/NoteQuestionParser.ts index cf61d332..80807946 100644 --- a/src/NoteQuestionParser.ts +++ b/src/NoteQuestionParser.ts @@ -8,7 +8,6 @@ import { SRSettings, SettingsUtil } from "./settings"; import { ISRFile } from "./SRFile"; import { TopicPath, TopicPathList } from "./TopicPath"; import { extractFrontmatter, splitTextIntoLineArray } from "./util/utils"; -import { testTimeLog } from "./util/DateProvider"; export class NoteQuestionParser { settings: SRSettings; @@ -42,16 +41,13 @@ export class NoteQuestionParser { this._hasTopicPaths = tagList.some((item) => SettingsUtil.isFlashcardTag(this.settings, item)) || folderTopicPath.hasPath; - testTimeLog("cql.A"); if (this._hasTopicPaths) { const noteText: string = await noteFile.read(); - testTimeLog(`cql.B\t${noteText.length}`); // Now that we know there are relevant flashcard tags in the file, we can get the more detailed info // that includes the line numbers of each tag const tagCacheList: TagCache[] = noteFile.getAllTagsFromText(); - testTimeLog("cql.C1"); // The following analysis can require fair computation. // There is no point doing it if there aren't any topic paths @@ -75,11 +71,8 @@ export class NoteQuestionParser { this.questionList = this.questionList.filter((q) => q.topicPathList); } } else { - testTimeLog("cql.B"); - testTimeLog("cql.C2"); this.questionList = [] as Question[]; } - testTimeLog("cql.D"); return this.questionList; } diff --git a/src/main.ts b/src/main.ts index deb85c46..91a5d2c3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -41,7 +41,6 @@ import { NoteEaseCalculator } from "./NoteEaseCalculator"; import { DeckTreeStatsCalculator } from "./DeckTreeStatsCalculator"; import { NoteEaseList } from "./NoteEaseList"; import { QuestionPostponementList } from "./QuestionPostponementList"; -import { testTimeFormatLapInfo, testTimeGetLapTime, testTimeLog, testTimeStart } from "./util/DateProvider"; interface PluginData { settings: SRSettings; @@ -89,13 +88,9 @@ export default class SRPlugin extends Plugin { public deckTree: Deck = new Deck("root", null); private remainingDeckTree: Deck; public cardStats: Stats; - private withFlashcardTagCount: number; - private hasChangedCount: number; - private withFlashcardCount: number; async onload(): Promise { await this.loadPluginData(); - console.log(`OSR: onload: bug-914-slow-load: D`); this.easeByPath = new NoteEaseList(this.data.settings); this.questionPostponementList = new QuestionPostponementList( this, @@ -354,11 +349,6 @@ export default class SRPlugin extends Plugin { } async sync(): Promise { - let markdownCount: number = 0; - this.withFlashcardTagCount = 0; - this.withFlashcardCount = 0; - this.hasChangedCount = 0; - if (this.syncLock) { return; } @@ -385,17 +375,8 @@ export default class SRPlugin extends Plugin { await this.savePluginData(); } - testTimeStart(); - let totalLapTime: number = 0; - let info: string = ""; const notes: TFile[] = this.app.vault.getMarkdownFiles(); for (const noteFile of notes) { - if (markdownCount != 0) { - info += `sync:\t${markdownCount}\t${testTimeFormatLapInfo()}\t`; - totalLapTime += testTimeGetLapTime(); - } - testTimeStart(); - markdownCount++; if ( this.data.settings.noteFoldersToIgnore.some((folder) => @@ -426,7 +407,6 @@ export default class SRPlugin extends Plugin { } const note: Note = await this.loadNote(noteFile); - testTimeLog("sync.A"); if (note.questionList.length > 0) { const flashcardsInNoteAvgEase: number = NoteEaseCalculator.Calculate( note, @@ -457,7 +437,6 @@ export default class SRPlugin extends Plugin { break; } } - testTimeLog("sync.B"); if (shouldIgnore) { continue; } @@ -493,12 +472,6 @@ export default class SRPlugin extends Plugin { this.reviewDecks[matchedNoteTag].scheduledNotes.push({ note: noteFile, dueUnix }); } } - if (markdownCount != 0) { - info += `sync:\t${markdownCount}\t${testTimeFormatLapInfo()}\t`; - totalLapTime += testTimeGetLapTime(); - } - console.log(`sync:\t${info}`); - console.log(`sync:\tTotalLapTime\t${totalLapTime}`); graph.rank(0.85, 0.000001, (node: string, rank: number) => { this.pageranks[node] = rank * 10000; @@ -517,13 +490,12 @@ export default class SRPlugin extends Plugin { const calc: DeckTreeStatsCalculator = new DeckTreeStatsCalculator(); this.cardStats = calc.calculate(this.deckTree); - console.log(`sync: markdownCount: ${markdownCount}, withFlashcardTagCount: ${this.withFlashcardTagCount}, withFlashcardCount: ${this.withFlashcardCount}, hasChangedCount: ${this.hasChangedCount}`); if (this.data.settings.showDebugMessages) { console.log(`SR: ${t("EASES")}`, this.easeByPath.dict); console.log(`SR: ${t("DECKS")}`, this.deckTree); } - if (this.data.settings.showDebugMessages || true) { + if (this.data.settings.showDebugMessages) { console.log( "SR: " + t("SYNC_TIME_TAKEN", { @@ -576,23 +548,17 @@ export default class SRPlugin extends Plugin { } async loadNote(noteFile: TFile): Promise { - testTimeLog("ln.A"); const loader: NoteFileLoader = new NoteFileLoader(this.data.settings); const srFile: ISRFile = this.createSrTFile(noteFile); const folderTopicPath: TopicPath = TopicPath.getFolderPathFromFilename( srFile, this.data.settings, ); - testTimeLog("ln.B"); const note: Note = await loader.load(this.createSrTFile(noteFile), folderTopicPath); - if (loader.hasTopicPaths) this.withFlashcardTagCount++; - if (note.questionList.length > 0) this.withFlashcardCount++; if (note.hasChanged) { - this.hasChangedCount++; note.writeNoteFile(this.data.settings); } - testTimeLog("ln.C"); return note; } From 42d8357ca67ff086ddac67de4d3f967f0affa527 Mon Sep 17 00:00:00 2001 From: ronzulu <75528127+ronzulu@users.noreply.github.com> Date: Mon, 8 Apr 2024 08:56:58 +1000 Subject: [PATCH 5/7] Removed detailed timing logging --- src/SRFile.ts | 4 ---- src/main.ts | 1 - 2 files changed, 5 deletions(-) diff --git a/src/SRFile.ts b/src/SRFile.ts index 3cfcc287..0587750d 100644 --- a/src/SRFile.ts +++ b/src/SRFile.ts @@ -1,7 +1,6 @@ import { MetadataCache, TFile, Vault, HeadingCache, getAllTags as ObsidianGetAllTags, TagCache, FrontMatterCache } from "obsidian"; import { parseObsidianFrontmatterTag } from "./util/utils"; -import { testTimeLog } from "./util/DateProvider"; export interface ISRFile { get path(): string; @@ -33,11 +32,8 @@ export class SrTFile implements ISRFile { } getAllTagsFromCache(): string[] { - testTimeLog("gatfc.A"); const fileCachedData = this.metadataCache.getFileCache(this.file) || {}; - testTimeLog("gatfc.B"); const result: string[] = ObsidianGetAllTags(fileCachedData) || []; - testTimeLog("gatfc.C"); return result; } diff --git a/src/main.ts b/src/main.ts index 91a5d2c3..a8c3c278 100644 --- a/src/main.ts +++ b/src/main.ts @@ -377,7 +377,6 @@ export default class SRPlugin extends Plugin { const notes: TFile[] = this.app.vault.getMarkdownFiles(); for (const noteFile of notes) { - if ( this.data.settings.noteFoldersToIgnore.some((folder) => noteFile.path.startsWith(folder), From f08c72f28127d3447eac509902369642b5dfacff Mon Sep 17 00:00:00 2001 From: ronzulu <75528127+ronzulu@users.noreply.github.com> Date: Mon, 8 Apr 2024 09:22:43 +1000 Subject: [PATCH 6/7] lint, format and update change log --- CHANGELOG.md | 2 +- CONTRIBUTING.md | 2 +- docs/changelog.md | 4 ++++ src/NoteQuestionParser.ts | 9 +++++---- src/SRFile.ts | 11 +++++++++-- src/util/TimeTestUtil.ts | 9 ++++----- tests/unit/helpers/UnitTestHelper.ts | 1 - 7 files changed, 24 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bed66b3..1cc39a66 120000 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1 @@ -docs/changelog.md \ No newline at end of file +docs/changelog.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 651dc17d..9815d5bd 120000 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1 +1 @@ -docs/en/contributing.md \ No newline at end of file +docs/en/contributing.md diff --git a/docs/changelog.md b/docs/changelog.md index 4d80a7d8..4cd65167 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [Unreleased] + +- [BUG] Very slow load of flashcard modal (since 1.11.2) [`#914`](https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/914) + #### [1.12.2](https://github.com/st3v3nmw/obsidian-spaced-repetition/compare/1.12.1...1.12.2) - fix bug with recognizing frontmatter topic tags (led to missing cards shown for review) [`#920`](https://github.com/st3v3nmw/obsidian-spaced-repetition/pull/920) diff --git a/src/NoteQuestionParser.ts b/src/NoteQuestionParser.ts index 80807946..dbc351cf 100644 --- a/src/NoteQuestionParser.ts +++ b/src/NoteQuestionParser.ts @@ -37,17 +37,18 @@ export class NoteQuestionParser { this.noteFile = noteFile; // For efficiency, we first get the tag list from the Obsidian cache // (this only gives the tag names, not the line numbers, but this is sufficient for this first step) - const tagList: string[] = noteFile.getAllTagsFromCache(); + const tagCacheList: string[] = noteFile.getAllTagsFromCache(); this._hasTopicPaths = - tagList.some((item) => SettingsUtil.isFlashcardTag(this.settings, item)) || + tagCacheList.some((item) => SettingsUtil.isFlashcardTag(this.settings, item)) || folderTopicPath.hasPath; if (this._hasTopicPaths) { + // Reading the file is relatively an expensive operation, so we only do this when needed const noteText: string = await noteFile.read(); // Now that we know there are relevant flashcard tags in the file, we can get the more detailed info // that includes the line numbers of each tag - const tagCacheList: TagCache[] = noteFile.getAllTagsFromText(); + const tagCompleteList: TagCache[] = noteFile.getAllTagsFromText(); // The following analysis can require fair computation. // There is no point doing it if there aren't any topic paths @@ -61,7 +62,7 @@ export class NoteQuestionParser { // For each question, determine it's TopicPathList [this.frontmatterTopicPathList, this.contentTopicPathInfo] = - this.analyseTagCacheList(tagCacheList); + this.analyseTagCacheList(tagCompleteList); for (const question of this.questionList) { question.topicPathList = this.determineQuestionTopicPathList(question); } diff --git a/src/SRFile.ts b/src/SRFile.ts index 0587750d..ce283567 100644 --- a/src/SRFile.ts +++ b/src/SRFile.ts @@ -1,5 +1,12 @@ -import { MetadataCache, TFile, Vault, HeadingCache, getAllTags as ObsidianGetAllTags, - TagCache, FrontMatterCache } from "obsidian"; +import { + MetadataCache, + TFile, + Vault, + HeadingCache, + getAllTags as ObsidianGetAllTags, + TagCache, + FrontMatterCache, +} from "obsidian"; import { parseObsidianFrontmatterTag } from "./util/utils"; export interface ISRFile { diff --git a/src/util/TimeTestUtil.ts b/src/util/TimeTestUtil.ts index 8017032f..c4064788 100644 --- a/src/util/TimeTestUtil.ts +++ b/src/util/TimeTestUtil.ts @@ -3,15 +3,15 @@ import moment from "moment"; // These functions were used to diagnose performance issue // https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/914 -var testTimeInfo: [ string, number ][]; +let testTimeInfo: [string, number][]; export function testTimeStart(): void { - testTimeInfo = [ [ "Start", moment().valueOf() ] ]; + testTimeInfo = [["Start", moment().valueOf()]]; } export function testTimeLog(desc: string): void { - if (testTimeInfo == null) testTimeStart(); - testTimeInfo.push([ desc, moment().valueOf() ]); + if (testTimeInfo == null) testTimeStart(); + testTimeInfo.push([desc, moment().valueOf()]); } export function testTimeGetLapTime(): number { @@ -29,4 +29,3 @@ export function testTimeFormatLapInfo(): string { result += `\tLapTime\t${testTimeGetLapTime()}|`; return result; } - diff --git a/tests/unit/helpers/UnitTestHelper.ts b/tests/unit/helpers/UnitTestHelper.ts index b5a60021..2864d16e 100644 --- a/tests/unit/helpers/UnitTestHelper.ts +++ b/tests/unit/helpers/UnitTestHelper.ts @@ -55,4 +55,3 @@ export function unitTest_GetAllTagsFromTextEx(text: string): TagCache[] { } return result; } - From 85e6e6c41d0baee26440f24eb0b0f7b8f303bcfc Mon Sep 17 00:00:00 2001 From: ronzulu <75528127+ronzulu@users.noreply.github.com> Date: Tue, 9 Apr 2024 10:51:43 +1000 Subject: [PATCH 7/7] Removed unused code caught by test coverage checks --- src/NoteFileLoader.ts | 6 ------ src/NoteQuestionParser.ts | 9 ++------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/NoteFileLoader.ts b/src/NoteFileLoader.ts index 89720d91..252e863b 100644 --- a/src/NoteFileLoader.ts +++ b/src/NoteFileLoader.ts @@ -11,11 +11,6 @@ export class NoteFileLoader { noteTopicPath: TopicPath; noteFile: ISRFile; settings: SRSettings; - private _hasTopicPaths: boolean; - - public get hasTopicPaths(): boolean { - return this._hasTopicPaths; - } constructor(settings: SRSettings) { this.settings = settings; @@ -32,7 +27,6 @@ export class NoteFileLoader { folderTopicPath, onlyKeepQuestionsWithTopicPath, ); - this._hasTopicPaths = questionParser.hasTopicPaths; const result: Note = new Note(noteFile, questionList); return result; diff --git a/src/NoteQuestionParser.ts b/src/NoteQuestionParser.ts index dbc351cf..208a03a7 100644 --- a/src/NoteQuestionParser.ts +++ b/src/NoteQuestionParser.ts @@ -19,11 +19,6 @@ export class NoteQuestionParser { frontmatterTopicPathList: TopicPathList; contentTopicPathInfo: TopicPathList[]; questionList: Question[]; - private _hasTopicPaths: boolean; - - public get hasTopicPaths(): boolean { - return this._hasTopicPaths; - } constructor(settings: SRSettings) { this.settings = settings; @@ -38,11 +33,11 @@ export class NoteQuestionParser { // For efficiency, we first get the tag list from the Obsidian cache // (this only gives the tag names, not the line numbers, but this is sufficient for this first step) const tagCacheList: string[] = noteFile.getAllTagsFromCache(); - this._hasTopicPaths = + const hasTopicPaths: boolean = tagCacheList.some((item) => SettingsUtil.isFlashcardTag(this.settings, item)) || folderTopicPath.hasPath; - if (this._hasTopicPaths) { + if (hasTopicPaths) { // Reading the file is relatively an expensive operation, so we only do this when needed const noteText: string = await noteFile.read();