tcl - 如何在 ICC 中并行处理 foreach_in_collection?
问题描述
有人可以帮我提供有关如何并行处理foreach_in_collection
循环的代码片段吗?我有一个庞大的集合网络/引脚/单元列表,我想循环访问它们。
以串行方式一个接一个地运行脚本需要几个小时。有没有办法让我的大列表分成几部分并让循环并行执行?
###########################################################################
#proc to trace back from input to driver through buffers/inverters
proc trace_back_bufinv { pin } {
set i 0;
set not_buf false;
set not_inv false;
while {1} {
set out [filter_collection [all_connected [get_flat_nets -of $pin] -leaf] "direction==out"]
if {[sizeof_collection $out] == 0} { set out [filter_collection [all_connected [get_flat_nets -of $pin] -leaf] "object_class==port"]}
set cc [get_flat_cells -of $out -quiet]
if {[sizeof_collection $cc] == 0 } { set cc [get_attribute $out design] }
if {[get_object_name $cc] == [get_attribute [get_designs] top_module_name]} {
set ref [get_attr [get_designs] top_module_name] } else { set ref [get_attr $cc ref_name] }
if {[regexp {_buf} $ref]} { set not_buf false; } else { set not_buf true}
if {[regexp {_inv} $ref]} { set not_inv false; } else { set not_inv true}
set pin [get_flat_pins -of $cc -filter "direction==in"]
incr i;
if {$not_inv && $not_buf} { return [get_object_name $out]; break }
}
}
#proc to trace front from output to loads through buffers/inverters
proc trace_front_bufinv { pin } {
redirect -variable testfront {report_buffer_trees -from $pin -hierarchy}
set sink {}
foreach line [split $testfront "\n"] {
if {[regexp -nocase {Load } $line]} { lappend sink [lindex $line end-1] }
}
return $sink;
}
#----------------------------------------------------------------------------------------------------------------------------------
set mod_cells [get_flat_cells -of ${module_cell} ]
set mod_cells_pins [get_flat_pins -of ${mod_cells} -filter "port_type==signal && name!=ret && name!=nret"]
foreach_in_collection mcc $mod_cells_pins {
incr i;
set direction [get_attribute $mcc direction]
if {$direction=="in"} {
set drivers [trace_back_bufinv $mcc]
set drivers [get_flat_pins $drivers -quiet]
set drivers [add_to_collection -unique $drivers [get_ports $drivers -quiet]]
set loads $mcc
} else {
set drivers $mcc
set loads [trace_front_bufinv $mcc]
set loads [get_flat_pins $loads -quiet]
set loads [add_to_collection -unique $loads [get_ports $loads -quiet]]
}
}
###########################################################################
解决方案
理论上,您创建一个适当配置的线程池(因为当您处理大量任务时,线程池比原始线程更容易管理),将所有任务放入池中,然后等待一切完成。复杂的部分是“适当配置”。首先,有要创建的线程数(经验法则是“创建更多,直到您在调整脚本时总体上没有获得有意义的更好的性能”,不,完全自动正确处理是非常棘手的)。
但其次,更重要的是,工作线程需要能够处理您分配给它们的任务。
如果您的任务是受 I/O 限制的,那么 Tcl 中的线程不太可能有太大帮助(因为 Tcl 实际上非常擅长异步 I/O),除非您碰巧在做一个只有 API 是同步的非常简短的事情之一。如果任务受内存限制,那么在您获得更多内存之前,线程是一个坏主意!只有在 CPU 密集型任务中,线程才能真正提供帮助。为了优化这一点,Tcl 的实现侧重于保持非常小的锁定量,它通过要求您在线程之间复制大部分状态来做到这一点;您可以使用共享变量,但这不是您默认获得的。并且您的在网络/引脚/单元上提供操作的代码需要以这种方式拆分或线程感知(如果需要,使用相关的锁)。这是一个主要要求;
也就是说,理论上你只需制作一个本地包(这里称为worker
),它提供每个工作线程的实现,然后执行:
package require Thread
set numThreads 8
set pool [tpool::create -maxworkers $numThreads -initcmd {
package require worker
}]
# Launch the tasks in the background
foreach_in_collection item $collection {
# worker::processItem is a command you define in the worker package
set task [tpool::post -nowait $pool [list \
worker::processItem $item]]
set tasks($task) $item
lappend inProgress $task
}
# Wait for them all to complete
while {[llength $inProgress]} {
foreach finished [tpool::wait $pool $inProgress inProgress] {
# Pick up the results from each of the finished tasks
set item $tasks($finished)
set result [tpool::get $pool $finished]
# Not sure what you want to do here
puts "$item mapped to $result"
}
}
原理很简单,但是制作一个有意义的worker
包对你来说真的很难。你不想让所有东西都排在一个巨大的全局锁后面;这种方式实际上可能会失去性能而不是获得它。
推荐阅读
- groovy - [Jmeter] 源单元“Script1.groovy”中的“语义分析”阶段异常 不支持的类文件主要版本 61
- r - 错误:缺少参数“expr”,没有默认值
- html - 包装时打破字母但不打破单词
- javascript - 将 Firebase 身份验证用于 Web 应用程序的最佳做法是什么?
- javascript - 过滤器:反转()页面上的所有项目,除了一个
- javascript - 使用变量来更改对象名称,并使用扩展运算符(Reactjs)
- reactjs - “不可分配”使用泛型进行排序的类型错误
- posix - Mac OS 中的 POSIX_NAME_MAX 值是否仅为 14?
- flutter - 修复 Flutter 打印包 UI
- azure-active-directory - 调用 .\auth\refresh 端点后 Azure 应用服务身份验证令牌未刷新