Skip to content

Commit

Permalink
Merge pull request #998 from golemfactory/mgordel/JST-1009/rename-con…
Browse files Browse the repository at this point in the history
…currency

refactor: renamed `concurrency` param to `poolSize`
  • Loading branch information
grisha87 authored Jun 27, 2024
2 parents 3514a93 + c68b2f4 commit 0be9128
Show file tree
Hide file tree
Showing 16 changed files with 94 additions and 108 deletions.
4 changes: 2 additions & 2 deletions examples/advanced/manual-pools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const demandOptions = {
const proposalSubscription = proposalPool.readFrom(draftProposal$);

/** How many providers you plan to engage simultaneously */
const CONCURRENCY = 2;
const PARALLELISM = 2;

const depModules = {
market: glm.market,
Expand All @@ -59,7 +59,7 @@ const demandOptions = {
};

const pool = depModules.rental.createResourceRentalPool(proposalPool, allocation, {
replicas: { max: CONCURRENCY },
poolSize: { max: PARALLELISM },
});

const rental1 = await pool.acquire();
Expand Down
6 changes: 3 additions & 3 deletions examples/advanced/override-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* therefore this feature is not recommended for most users.
*/

import { Concurrency, MarketOrderSpec, GolemNetwork } from "@golem-sdk/golem-js";
import { MarketOrderSpec, GolemNetwork } from "@golem-sdk/golem-js";
import { pinoPrettyLogger } from "@golem-sdk/pino-logger";

// let's override the `estimateBudget` method from the `MarketModule` interface
Expand All @@ -15,9 +15,9 @@ import { pinoPrettyLogger } from "@golem-sdk/pino-logger";
import { MarketModuleImpl } from "@golem-sdk/golem-js";

class MyMarketModule extends MarketModuleImpl {
estimateBudget({ concurrency, order }: { concurrency: Concurrency; order: MarketOrderSpec }): number {
estimateBudget({ maxAgreements, order }: { maxAgreements: number; order: MarketOrderSpec }): number {
// let's take the original estimate and add 20% to it as a buffer
const originalEstimate = super.estimateBudget({ concurrency, order });
const originalEstimate = super.estimateBudget({ maxAgreements, order });
return originalEstimate * 1.2;
}
}
Expand Down
2 changes: 1 addition & 1 deletion examples/advanced/setup-and-teardown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ U2FsdGVkX18jQbGQ7KTAaRask5efrXEWvvGhe4jQ0MT9mwwH4ULjvoWDm1mNlsjYtb1nRt0O6iBd4O9m
.then(() => console.log("Removed the encrypted messages from the provider %s", exe.provider.name));

const pool = await glm.manyOf({
concurrency: { max: 3 }, // I want to decrypt in parallel on a maximum of 3 machines simultaneously
poolSize: { max: 3 }, // I want to decrypt in parallel on a maximum of 3 machines simultaneously
order,
setup,
teardown,
Expand Down
2 changes: 1 addition & 1 deletion examples/advanced/step-by-step.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import { filter, map, switchMap, take } from "rxjs";
// Allocate funds to cover the order, we will only pay for the actual usage
// so any unused funds will be returned to us at the end
allocation = await glm.payment.createAllocation({
budget: glm.market.estimateBudget({ order, concurrency: 1 }),
budget: glm.market.estimateBudget({ order, maxAgreements: 1 }),
expirationSec: order.market.rentHours * 60 * 60,
});

Expand Down
2 changes: 1 addition & 1 deletion examples/basic/many-of.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const order: MarketOrderSpec = {
await glm.connect();
// create a pool that can grow up to 3 rentals at the same time
const pool = await glm.manyOf({
concurrency: 3,
poolSize: 3,
order,
});
await Promise.allSettled([
Expand Down
2 changes: 1 addition & 1 deletion examples/basic/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const order: MarketOrderSpec = {
try {
await glm.connect();
const pool = await glm.manyOf({
concurrency: 2,
poolSize: 2,
order,
});
const rental1 = await pool.acquire();
Expand Down
2 changes: 1 addition & 1 deletion examples/basic/vpn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { pinoPrettyLogger } from "@golem-sdk/pino-logger";
};
// create a pool that can grow up to 2 rentals at the same time
const pool = await glm.manyOf({
concurrency: 2,
poolSize: 2,
order,
});
const rental1 = await pool.acquire();
Expand Down
27 changes: 20 additions & 7 deletions src/experimental/deployment/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,28 @@ export class Deployment {
// be the equal to the longest expiration date of all demands
const longestExpiration =
Math.max(...this.components.resourceRentalPools.map((pool) => pool.options.market.rentHours)) * 3600;
const totalBudget = this.components.resourceRentalPools.reduce(
(acc, pool) =>

const totalBudget = this.components.resourceRentalPools.reduce((acc, pool) => {
const maxAgreements = (() => {
if (typeof pool.options.deployment.replicas === "number") {
return pool.options.deployment.replicas;
}
if (pool.options.deployment.replicas.max) {
return pool.options.deployment.replicas.max;
}
if (pool.options.deployment.replicas.min) {
return pool.options.deployment.replicas.min;
}
return 1;
})();
return (
acc +
this.modules.market.estimateBudget({
order: pool.options,
concurrency: pool.options.deployment.replicas,
}),
0,
);
maxAgreements,
})
);
}, 0);

const allocation = await this.modules.payment.createAllocation({
budget: totalBudget,
Expand Down Expand Up @@ -166,7 +179,7 @@ export class Deployment {
const proposalSubscription = proposalPool.readFrom(draftProposal$);

const resourceRentalPool = this.modules.rental.createResourceRentalPool(proposalPool, allocation, {
replicas: pool.options.deployment?.replicas,
poolSize: pool.options.deployment?.replicas,
network,
resourceRentalOptions: {
activity: pool.options?.activity,
Expand Down
4 changes: 2 additions & 2 deletions src/golem-network/golem-network.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ describe("Golem Network", () => {
await glm.connect();

const pool = await glm.manyOf({
concurrency: 3,
poolSize: 3,
order,
});

Expand All @@ -171,7 +171,7 @@ describe("Golem Network", () => {
await glm.connect();

const pool = await glm.manyOf({
concurrency: 3,
poolSize: 3,
order: {
...order,
payment: {
Expand Down
40 changes: 27 additions & 13 deletions src/golem-network/golem-network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { ActivityModule, ActivityModuleImpl, ExeUnitOptions, IActivityApi, IFile
import { INetworkApi, Network, NetworkModule, NetworkModuleImpl, NetworkOptions } from "../network";
import { EventEmitter } from "eventemitter3";
import {
Concurrency,
PoolSize,
RentalModule,
RentalModuleImpl,
ResourceRental,
Expand Down Expand Up @@ -150,7 +150,7 @@ export interface OneOfOptions {

export interface ManyOfOptions {
order: MarketOrderSpec;
concurrency: Concurrency;
poolSize: PoolSize;
setup?: ExeUnitOptions["setup"];
teardown?: ExeUnitOptions["teardown"];
}
Expand Down Expand Up @@ -332,13 +332,13 @@ export class GolemNetwork {

private async getAllocationFromOrder({
order,
concurrency,
maxAgreements,
}: {
order: MarketOrderSpec;
concurrency: Concurrency;
maxAgreements: number;
}): Promise<Allocation> {
if (!order.payment?.allocation) {
const budget = this.market.estimateBudget({ order, concurrency });
const budget = this.market.estimateBudget({ order, maxAgreements });
return this.payment.createAllocation({
budget,
expirationSec: order.market.rentHours * 60 * 60,
Expand Down Expand Up @@ -378,7 +378,7 @@ export class GolemNetwork {
selectOfferProposal: order.market.offerProposalSelector,
});

const allocation = await this.getAllocationFromOrder({ order, concurrency: 1 });
const allocation = await this.getAllocationFromOrder({ order, maxAgreements: 1 });
const demandSpecification = await this.market.buildDemandDetails(order.demand, allocation);

const draftProposal$ = this.market.collectDraftOfferProposals({
Expand Down Expand Up @@ -434,13 +434,13 @@ export class GolemNetwork {

/**
* Define your computational resource demand and access a pool of instances.
* The pool will grow up to the specified concurrency level.
* The pool will grow up to the specified poolSize.
*
* @example
* ```ts
* // create a pool that can grow up to 3 rentals at the same time
* const pool = await glm.manyOf({
* concurrency: 3,
* poolSize: 3,
* demand
* });
* await Promise.allSettled([
Expand All @@ -465,20 +465,34 @@ export class GolemNetwork {
* ]);
* ```
*
* @param @param {Object} options
* @param {Object} options
* @param options.order - represents the order specifications which will result in access to LeaseProcess.
* @param options.concurrency - concurrency level, can be defined as a number or an object with min and max fields
* @param options.poolSize {Object | number} - can be defined as a number or an object with min and max fields, if defined as a number it will be treated as a min parameter.
* @param options.poolSize.min - the minimum pool size to achieve ready state (default = 0)
* @param options.poolSize.max - the maximum pool size, if reached, the next pool element will only be available if the borrowed resource is released or destroyed (dafault = 100)
* @param options.setup - an optional function that is called as soon as the exe unit is ready
* @param options.teardown - an optional function that is called before the exe unit is destroyed
*/
public async manyOf({ concurrency, order, setup, teardown }: ManyOfOptions): Promise<ResourceRentalPool> {
public async manyOf({ poolSize, order, setup, teardown }: ManyOfOptions): Promise<ResourceRentalPool> {
const proposalPool = new DraftOfferProposalPool({
logger: this.logger,
validateOfferProposal: order.market.offerProposalFilter,
selectOfferProposal: order.market.offerProposalSelector,
});

const allocation = await this.getAllocationFromOrder({ order, concurrency });
const maxAgreements = (() => {
if (typeof poolSize === "number") {
return poolSize;
}
if (poolSize.max) {
return poolSize.max;
}
if (poolSize.min) {
return poolSize.min;
}
return 1;
})();
const allocation = await this.getAllocationFromOrder({ order, maxAgreements });
const demandSpecification = await this.market.buildDemandDetails(order.demand, allocation);

const draftProposal$ = this.market.collectDraftOfferProposals({
Expand All @@ -489,7 +503,7 @@ export class GolemNetwork {
const subscription = proposalPool.readFrom(draftProposal$);

const resourceRentalPool = this.rental.createResourceRentalPool(proposalPool, allocation, {
replicas: concurrency,
poolSize,
network: order.network,
resourceRentalOptions: {
activity: order.activity,
Expand Down
41 changes: 7 additions & 34 deletions src/market/market.module.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ describe("Market module", () => {
});
});
describe("estimateBudget()", () => {
it("estimates budget for the exact concurrency level", () => {
it("estimates budget for max number of agreeements", () => {
const order: MarketOrderSpec = {
demand: {
workload: {
Expand All @@ -597,40 +597,13 @@ describe("Market module", () => {
},
},
};
const concurrency = 3;
const maxAgreements = 10;
const cpuPrice = 0.5 * 5 * 5; // 5 threads for 0.5 per hour for 5 hours
const envPrice = 2 * 5; // 2 per hour for 5 hours
const totalPricePerMachine = 1 + cpuPrice + envPrice;
const expectedBudget = totalPricePerMachine * concurrency;
const expectedBudget = totalPricePerMachine * maxAgreements;

const budget = marketModule.estimateBudget({ order, concurrency });
expect(budget).toBeCloseTo(expectedBudget, 5);
});
it("estimates budget for max concurrency level", () => {
const order: MarketOrderSpec = {
demand: {
workload: {
imageTag: "image",
minCpuThreads: 5,
},
},
market: {
rentHours: 5,
pricing: {
model: "linear",
maxStartPrice: 1,
maxEnvPerHourPrice: 2,
maxCpuPerHourPrice: 0.5,
},
},
};
const concurrency = { max: 10 };
const cpuPrice = 0.5 * 5 * 5; // 5 threads for 0.5 per hour for 5 hours
const envPrice = 2 * 5; // 2 per hour for 5 hours
const totalPricePerMachine = 1 + cpuPrice + envPrice;
const expectedBudget = totalPricePerMachine * concurrency.max;

const budget = marketModule.estimateBudget({ order, concurrency });
const budget = marketModule.estimateBudget({ order, maxAgreements });
expect(budget).toBeCloseTo(expectedBudget, 5);
});
it("estimates budget for non-linear pricing model", () => {
Expand All @@ -648,10 +621,10 @@ describe("Market module", () => {
},
},
};
const concurrency = 3;
const expectedBudget = 5 * 2 * concurrency;
const maxAgreements = 3;
const expectedBudget = 5 * 2 * maxAgreements;

const budget = marketModule.estimateBudget({ order, concurrency });
const budget = marketModule.estimateBudget({ order, maxAgreements });
expect(budget).toBeCloseTo(expectedBudget, 5);
});
});
Expand Down
20 changes: 3 additions & 17 deletions src/market/market.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import { GolemAbortError, GolemTimeoutError, GolemUserError } from "../shared/er
import { MarketOrderSpec } from "../golem-network";
import { INetworkApi, NetworkModule } from "../network";
import { AgreementOptions } from "./agreement/agreement";
import { Concurrency } from "../resource-rental";

export type DemandEngine = "vm" | "vm-nvidia" | "wasmtime";

Expand Down Expand Up @@ -178,13 +177,12 @@ export interface MarketModule {
}): Observable<OfferProposal>;

/**
* Estimate the budget for the given order and concurrency level.
* Estimate the budget for the given order and maximum numbers of agreemnets.
* Keep in mind that this is just an estimate and the actual cost may vary.
* To get a more accurate estimate, make sure to specify an exact or maximum concurrency level.
* The method returns the estimated budget in GLM.
* @param params
*/
estimateBudget({ concurrency, order }: { concurrency: Concurrency; order: MarketOrderSpec }): number;
estimateBudget({ maxAgreements, order }: { maxAgreements: number; order: MarketOrderSpec }): number;
/**
* Fetch the most up-to-date agreement details from the yagna
*/
Expand Down Expand Up @@ -559,25 +557,13 @@ export class MarketModuleImpl implements MarketModule {
});
}

estimateBudget({ concurrency, order }: { concurrency: Concurrency; order: MarketOrderSpec }): number {
estimateBudget({ order, maxAgreements }: { order: MarketOrderSpec; maxAgreements: number }): number {
const pricingModel = order.market.pricing.model;

// TODO: Don't assume for the user, at least not on pure golem-js level
const minCpuThreads = order.demand.workload?.minCpuThreads ?? 1;

const { rentHours } = order.market;
const maxAgreements = (() => {
if (typeof concurrency === "number") {
return concurrency;
}
if (concurrency.max) {
return concurrency.max;
}
if (concurrency.min) {
return concurrency.min;
}
return 1;
})();

switch (pricingModel) {
case "linear": {
Expand Down
2 changes: 1 addition & 1 deletion src/resource-rental/rental.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export class RentalModuleImpl implements RentalModule {
resourceRentalOptions: options?.resourceRentalOptions,
logger: this.deps.logger.child("resource-rental-pool"),
network: options?.network,
replicas: options?.replicas,
poolSize: options?.poolSize,
});
}
}
2 changes: 1 addition & 1 deletion src/resource-rental/resource-rental-pool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function getRentalPool(replicas: RequireAtLeastOne<{ min: number; max: number }>
rentalModule: instance(rentalModule),
logger: instance(imock<Logger>()),
network: undefined,
replicas,
poolSize: replicas,
});
}

Expand Down
Loading

0 comments on commit 0be9128

Please sign in to comment.