Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Count 429 errors #7

Merged
merged 6 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions .github/generateReport.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ function generateReport(title, dirName, mutantsDirName){

function generateLLMorpheusReport(title, dirName, mutantsDirName){
let report = `# ${title}\n`
report += '| Project | #Prompts | #Mutants | #Killed | #Survived | #Timeout | MutationScore | LLMorpheus Time | Stryker Time | #Prompt Tokens | #Completion Tokens | #Total Tokens |\n';
report += '|:--------|:---------|:---------|:--------|:----------|----------|---------------|-----------------|--------------|----------------|--------------------|----------------|\n';
report += '| Project | #Prompts | #Mutants | #Killed | #Survived | #Timeout | MutationScore | LLMorpheus Time | Stryker Time | #Prompt Tokens | #Completion Tokens | #Total Tokens | #Retries | # Failures |\n';
report += '|:--------|:---------|:---------|:--------|:----------|----------|---------------|-----------------|--------------|----------------|--------------------|----------------|----------|------------|\n';
const files = fs.readdirSync(dirName);
let totalMutants = 0;
let totalKilled = 0;
Expand All @@ -23,6 +23,8 @@ function generateLLMorpheusReport(title, dirName, mutantsDirName){
let totalPromptTokens = 0;
let totalCompletionTokens = 0;
let totalTotalTokens = 0;
let totalNrRetries = 0;
let totalNrFailures = 0;
for (const benchmark of files) {
const data = fs.readFileSync(`${dirName}/${benchmark}/StrykerInfo.json`, 'utf8');
const jsonObj = JSON.parse(data);
Expand Down Expand Up @@ -54,9 +56,13 @@ function generateLLMorpheusReport(title, dirName, mutantsDirName){
totalCompletionTokens += nrCompletionTokens;
const nrTotalTokens = llmJsonObj.totalTokens;
totalTotalTokens += nrTotalTokens;
report += `| ${benchmark} | ${nrPrompts} | ${nrTotal} | ${nrKilled} | ${nrSurvived} | ${nrTimedOut} | ${mutationScore} | ${llmorpheusTime} | ${strykerTime} | ${nrPromptTokens} | ${nrCompletionTokens} | ${nrTotalTokens} |\n`;
nrRetries = llmJsonObj.nrRetries;
totalNrRetries += nrRetries;
nrFailures = llmJsonObj.nrFailures;
totalNrFailures += nrFailures;
report += `| ${benchmark} | ${nrPrompts} | ${nrTotal} | ${nrKilled} | ${nrSurvived} | ${nrTimedOut} | ${mutationScore} | ${llmorpheusTime} | ${strykerTime} | ${nrPromptTokens} | ${nrCompletionTokens} | ${nrTotalTokens} | ${nrRetries} | ${nrFailures} |\n`;
}
report += `| Total | ${totalPrompts} | ${totalMutants} | ${totalKilled} | ${totalSurvived} | ${totalTimedOut} | - | ${totalLLMorpheusTime.toFixed(2)} | ${totalStrykerTime.toFixed(2)} | ${totalPromptTokens} | ${totalCompletionTokens} | ${totalTotalTokens} |\n`;
report += `| Total | ${totalPrompts} | ${totalMutants} | ${totalKilled} | ${totalSurvived} | ${totalTimedOut} | - | ${totalLLMorpheusTime.toFixed(2)} | ${totalStrykerTime.toFixed(2)} | ${totalPromptTokens} | ${totalCompletionTokens} | ${totalTotalTokens} | ${totalNrRetries} | ${totalNrFailures} |\n`;

const metaData = retrieveMetaData(mutantsDirName);

Expand Down
5 changes: 5 additions & 0 deletions src/generator/MutantGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,8 @@ export class MutantGenerator {
const nrSyntacticallyInvalid = this.mutationStats.nrSyntacticallyInvalid;
const nrIdentical = this.mutationStats.nrIdentical;
const nrDuplicate = this.mutationStats.nrDuplicate;
const nrRetries = this.model.getFailureCounter().nrRetries;
const nrFailures = this.model.getFailureCounter().nrFailures;
fs.writeFileSync(
resultsFileName,
JSON.stringify(
Expand All @@ -428,11 +430,14 @@ export class MutantGenerator {
totalCompletionTokens: this.mutationStats.totalCompletionTokens,
totalTokens: this.mutationStats.totalTokens,
metaInfo: this.metaInfo,
nrRetries,
nrFailures,
},
null,
2
)
);
console.log(`nrRetries = ${nrRetries}, nrFailures = ${nrFailures}`);
console.log(`summary written to ${resultsFileName}\n`);

this.printAndLog(
Expand Down
7 changes: 6 additions & 1 deletion src/model/CachingModel.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from "fs";
import path from "path";
import crypto from "crypto";
import { IModel } from "./IModel";
import { IModel, IModelFailureCounter } from "./IModel";
import { PostOptions, defaultPostOptions } from "./IModel";
import { IQueryResult } from "./IQueryResult";

Expand All @@ -19,6 +19,11 @@ export class CachingModel implements IModel {
this.modelName = `${model.getModelName()}`;
console.log(`Using cache dir: ${cacheDir}`);
}

getFailureCounter(): IModelFailureCounter {
return this.model.getFailureCounter();
}

getModelName(): string {
return `${this.modelName}`;
}
Expand Down
6 changes: 6 additions & 0 deletions src/model/IModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface IModel {
getModelName(): string;
getTemperature(): number;
getMaxTokens(): number;
getFailureCounter(): IModelFailureCounter;
}

export const defaultPostOptions = {
Expand All @@ -27,3 +28,8 @@ export const defaultOpenAIPostoptions = {

export type PostOptions = Partial<typeof defaultPostOptions>;
export type OpenAIPostOptions = Partial<typeof defaultOpenAIPostoptions>;

export interface IModelFailureCounter {
nrRetries: number;
nrFailures: number;
}
6 changes: 5 additions & 1 deletion src/model/MockModel.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from "fs";
import path from "path";
import crypto from "crypto";
import { IModel } from "./IModel";
import { IModel, IModelFailureCounter } from "./IModel";
import { defaultPostOptions } from "./IModel";
import { IQueryResult } from "./IQueryResult";

Expand All @@ -16,6 +16,10 @@ export class MockModel implements IModel {
this.modelName = `${modelName}`;
}

getFailureCounter(): IModelFailureCounter {
return { nrRetries: 0, nrFailures: 0 };
}

getModelName(): string {
return this.modelName;
}
Expand Down
13 changes: 11 additions & 2 deletions src/model/Model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
RateLimiter,
} from "../util/promise-utils";
import { retry } from "../util/promise-utils";
import { IModel } from "./IModel";
import { IModel, IModelFailureCounter } from "./IModel";
import { PostOptions, defaultPostOptions } from "./IModel";
import { getEnv } from "../util/code-utils";
import { IQueryResult } from "./IQueryResult";
Expand All @@ -26,6 +26,7 @@ export class Model implements IModel {

protected instanceOptions: PostOptions;
protected rateLimiter: RateLimiter;
protected counter: IModelFailureCounter = { nrRetries: 0, nrFailures: 0 };

constructor(
private modelName: string,
Expand Down Expand Up @@ -114,11 +115,15 @@ export class Model implements IModel {
headers: Model.LLMORPHEUS_LLM_AUTH_HEADERS,
})
),
this.metaInfo.nrAttempts
this.metaInfo.nrAttempts,
() => {
this.counter.nrRetries++;
}
);
} catch (e) {
if (res?.status === 429) {
console.error(`*** 429 error: ${e}`);
this.counter.nrFailures++;
}
throw e;
}
Expand Down Expand Up @@ -155,4 +160,8 @@ export class Model implements IModel {
total_tokens,
};
}

public getFailureCounter(): IModelFailureCounter {
return this.counter;
}
}
6 changes: 5 additions & 1 deletion src/model/ReplayModel.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import fs from "fs";
import path from "path";
import { IModel } from "./IModel";
import { IModel, IModelFailureCounter } from "./IModel";
import { IQueryResult } from "./IQueryResult";
import { MetaInfo } from "../generator/MetaInfo";

Expand All @@ -21,6 +21,10 @@ export class ReplayModel implements IModel {
this.initializeMap();
}

getFailureCounter(): IModelFailureCounter {
return { nrFailures: 0, nrRetries: 0 };
}

/**
* Initialize a map from prompts to completions by inspecting the contents
* of the "prompts" subdirectory
Expand Down
7 changes: 6 additions & 1 deletion src/util/promise-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
* This function provides supports for retrying the creation of a promise
* up to a given number of times in case the promise is rejected.
* This is useful for, e.g., retrying a request to a server that is temporarily unavailable.
* Invokes notifyFun after each rejection.
*
*/
export async function retry<T>(
f: () => Promise<T>,
howManyTimes: number
howManyTimes: number,
notifyFun: () => void
): Promise<T> {
let i = 1;
let promise: Promise<T> = f(); // create the promise, but don't wait for its fulfillment yet..
Expand All @@ -19,6 +21,9 @@ export async function retry<T>(
return val; // if the promise was fulfilled, return another promise that is fulfilled with the same value
} catch (e) {
i++;
if (notifyFun !== undefined) {
notifyFun();
}
console.log(`Promise rejected with ${e}.`);
promise = f(); // next attempt: create the promise, but don't wait for its fulfillment yet..
}
Expand Down
4 changes: 3 additions & 1 deletion test/expected/summary.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@
"ignore": "src/**/*.spec.ts",
"rateLimit": 1000,
"benchmark": false
}
},
"nrRetries": 0,
"nrFailures": 0
}
Loading