Replies: 14 comments 42 replies
-
I like the idea, but I think I would make a modification to a builder architecture, which I think makes sense for two reasons.
class ToolOptionsBuilder : OptionBuilder {
public:
/*
* Not necessarily required in all cases, but could help build default options for a particular PDK, or
* core size etc.
*/
ToolOptionsBuilder(Design *);
void setOptionA(int A);
void setOptionB(bool B);
ErrorOr<ToolOptions> create(); // could also throw an exception.
}
class ToolOptions : ToolOption{
private:
ToolOptions(int A, bool B); // a well-defined default state
public:
int getOptionA();
bool getOptionB();
};
class Tool {
public:
static ToolOptions* getDefaultOptions(); // calls ToolOptionsBuilder(...).create();
// if options is nullptr then the default options are used.
void task(ToolOptions* options = nullptr);
};
I don't like the idea of modifying the default options object, seems very error prone.
I like this model, but with the builder pattern.
I think this is a greate idea too.
I like this but again should be constructed using builders.
I think there's also another problem
I've thought about it a bunch, and I think storing a hidden only history from a user is probably not the right API instead I suggest. class Tool {
public:
static ToolOptions* getDefaultOptions(); // calls ToolOptionsBuilder(...).create();
set incrementalOptions(ToolOptions* options);
// if options is nullptr then the default options are used.
void task(ToolOptions* options = nullptr);
private:
ToolOptions* incremental_options_;
}; On construction the incrementalOptions are set to what's provided in the constructor, or can be updated by the user. This brings up another question about incremental APIs. @maliberty how do you envision a tool getting access to a |
Beta Was this translation helpful? Give feedback.
-
It's a very interesting question and I feel like I've become jaded because of how inconsistent commercial tools are. It seems like tools (both commercial and OpenROAD) always consist of some combination of the three options you mentioned. What's worse is that commercial tools can be some kind of weird blend of global variables, app variables, tool variables, etc. all with different methods for accessing them... it can get overwhelming. I think for the most part, I like the idea of doing away with arguments to commands and having all options passed through some kind of options object. The caveat is that I am split on whether that's appropriate for very simple commands that only take one parameter, like Whatever the decision is, I definitely want to see a common command / interface that lets a user easily query all parameters that can be set for a tool. For example:
Hidden state / parameters is one of the things I hate the most about commercial tools. At the same time, a user definitely shouldn't need to set parameters they don't know about, like bin grid size for GPL. These comments are mostly concerning the user-side interface. As for the developer / C++ API, I don't think I have strong opinions. I think the proposed interface sounds ok. |
Beta Was this translation helpful? Give feedback.
-
I'm lukewarm on a builder. Your two arguments for it were: "It allows you to do more validation in your builder". You can just as easily do this validation in the task. If you want to do it in the builder then you will have to restrict when it can be used (ie not before the db is populated) which seems awkward. The builder itself will have to be constructed by the tool to give it enough state for validation. "I like the idea of ToolOptions being an Immutable object. It means that a tool cannot modify the options which I think reduces the possibility of tools doing weird things with user provided options." I see two problems. The tool can always clone the options object and do "weird things". In gpl for example we set options before calling grt (see OpenROAD/src/gpl/src/routeBase.cpp Line 374 in b632f9f |
Beta Was this translation helpful? Give feedback.
-
re "I don't like the idea of modifying the default options object, seems very error prone." I have a somewhat similar feeling but I'm also afraid of producing very complex API calls (eg gpl). I think some people would prefer to setup the tools upfront. Also interactively it will save a lot of typing. However I am fine to remove it if there is a consensus that it isn't useful. |
Beta Was this translation helpful? Give feedback.
-
Putting the options in the db will open it up to tons of schema updates which is undesirable. Or we would have to make the storage extremely generic which will push the validation on load problem to each tool which isn't much better. Its also error prone for the user. I lean toward saying that on reload you don't get any incremental operations. We are living with that today, sta is not incremental across restart. |
Beta Was this translation helpful? Give feedback.
-
Sorry it's taken me a minute to respond to this- perhaps I can offer a bit of a different perspective being more on the user side, but:
ToolOptions options;
options.setOptionB(false);
tool->task(options); From where I stand, the above model would let me write a single common file to convert OpenLane variables to an OpenROAD ToolOptions object generator, which can then be passed onto other tools. |
Beta Was this translation helpful? Give feedback.
-
@rovinski tcl is a completely different API with lots of manual coding. Converting it look like python, if possible, would introduce the same friction of it looking nothing like usual EDA tools' tcl interface. I don't think it is worth the effort to maintain two sets of APIs. Klayout supporting both python & ruby is much simpler since they are both OO languages. We could do that too more easily (though I have no desire to). |
Beta Was this translation helpful? Give feedback.
-
Based on the discussions I'm wondering if it is preferrable to eliminate the global state and use only explicit options with a default arg:
|
Beta Was this translation helpful? Give feedback.
-
Should probably add- syntactic sugar in the form of auto options = ToolOptions {
{"a", "value1"},
{"b", "value2"}
}; i.e., one that basically takes a dict, with the appropriate bridging to python: options = ToolOptions(
a="value1",
b="value2",
) would be pretty cool |
Beta Was this translation helpful? Give feedback.
-
For a next step I want to make a concrete example. Looking at gpl it fits this model well is it is a single task (placement) with many options. When I look at ifp it is more problematic. It is a tool with multiple semi-related tasks: initFloorplan, insertTieCells, and makeTracks. I don't feel it makes sense to have a single options object to cover such diverse tasks. Perhaps this would be better formulated as TaskOptions rather than ToolOptions. A TaskOptions could replace the need for overloaded methods. This does run the risk of a proliferation of classes - worst case is one for every method. I am hopeful that the number of tasks is fairly limited per tool today. |
Beta Was this translation helpful? Give feedback.
-
I created #2809 as a example of what the revised API for gpl could look like. The user tcl layer is unchanged but python and c++ see a new options object. Replace has way too many options so it produces a very large object interface. Having made the change I'm a bit on the fence about keeping it like this versus making either (1) a code generator from a description file or (2) a more weakly typed interface using string (or enum) keys with a variant value and a single get/set method. I'm glad to hear opinions. |
Beta Was this translation helpful? Give feedback.
-
Any thoughts on either the existing approach or my other suggestion? |
Beta Was this translation helpful? Give feedback.
-
I came across https://abseil.io/tips/173 which gives some nice ideas for using designated initializers |
Beta Was this translation helpful? Give feedback.
-
The python api differs from tcl in being more OO (objects/methods) rather than command oriented. I'd like to discuss standardizing how that API accept options. Current APIs are variable:
Complicating cases are:
My best thought on how to standardize is to have a persistent set of default options and the ability to pass an overriding set. A sketch of the idea:
One use model would be pre-configuration (in C++ but similarly in python)
Another use model could be
This can be extended to the case of one tool calling another internally with an API like:
For a sufficiently complicated tool the options object could itself become a sub-configuration builder. For example:
The case of an incremental tool is tricky. If asked to do an update I think it should do so according to the last set of options (default or not) that it used. This implies that it must keep a copy of any non-default options object.
I'm open to other ideas or improvements. I'd love to hear from folks @gadfort @macd @QuantamHD @cdleary @osamahammad21 @antonblanchard @donn @rovinski
Beta Was this translation helpful? Give feedback.
All reactions