gem5 v24.0.0.0
Loading...
Searching...
No Matches
GarnetNetwork.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Advanced Micro Devices, Inc.
3 * Copyright (c) 2008 Princeton University
4 * Copyright (c) 2016 Georgia Institute of Technology
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met: redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer;
11 * redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution;
14 * neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
33
34#include <cassert>
35
36#include "base/cast.hh"
37#include "base/compiler.hh"
38#include "debug/RubyNetwork.hh"
48
49namespace gem5
50{
51
52namespace ruby
53{
54
55namespace garnet
56{
57
58/*
59 * GarnetNetwork sets up the routers and links and collects stats.
60 * Default parameters (GarnetNetwork.py) can be overwritten from command line
61 * (see configs/network/Network.py)
62 */
63
65 : Network(p)
66{
67 m_num_rows = p.num_rows;
68 m_ni_flit_size = p.ni_flit_size;
70 m_buffers_per_data_vc = p.buffers_per_data_vc;
71 m_buffers_per_ctrl_vc = p.buffers_per_ctrl_vc;
72 m_routing_algorithm = p.routing_algorithm;
74
75 m_enable_fault_model = p.enable_fault_model;
77 fault_model = p.fault_model;
78
80
81 for (int i = 0 ; i < m_virtual_networks ; i++) {
82 if (m_vnet_type_names[i] == "response")
83 m_vnet_type[i] = DATA_VNET_; // carries data (and ctrl) packets
84 else
85 m_vnet_type[i] = CTRL_VNET_; // carries only ctrl packets
86 }
87
88 // record the routers
89 for (std::vector<BasicRouter*>::const_iterator i = p.routers.begin();
90 i != p.routers.end(); ++i) {
91 Router* router = safe_cast<Router*>(*i);
92 m_routers.push_back(router);
93
94 // initialize the router's network pointers
95 router->init_net_ptr(this);
96 }
97
98 // record the network interfaces
100 i != p.netifs.end(); ++i) {
102 m_nis.push_back(ni);
103 ni->init_net_ptr(this);
104 }
105
106 // Print Garnet version
107 inform("Garnet version %s\n", garnetVersion);
108}
109
110void
112{
114
115 for (int i=0; i < m_nodes; i++) {
116 m_nis[i]->addNode(m_toNetQueues[i], m_fromNetQueues[i]);
117 }
118
119 // The topology pointer should have already been initialized in the
120 // parent network constructor
121 assert(m_topology_ptr != NULL);
123
124 // Initialize topology specific parameters
125 if (getNumRows() > 0) {
126 // Only for Mesh topology
127 // m_num_rows and m_num_cols are only used for
128 // implementing XY or custom routing in RoutingUnit.cc
131 assert(m_num_rows * m_num_cols == m_routers.size());
132 } else {
133 m_num_rows = -1;
134 m_num_cols = -1;
135 }
136
137 // FaultModel: declare each router to the fault model
138 if (isFaultModelEnabled()) {
140 i != m_routers.end(); ++i) {
141 Router* router = safe_cast<Router*>(*i);
142 [[maybe_unused]] int router_id =
144 router->get_num_outports(),
145 router->get_vc_per_vnet(),
148 assert(router_id == router->get_id());
149 router->printAggregateFaultProbability(std::cout);
150 router->printFaultVector(std::cout);
151 }
152 }
153}
154
155/*
156 * This function creates a link from the Network Interface (NI)
157 * into the Network.
158 * It creates a Network Link from the NI to a Router and a Credit Link from
159 * the Router to the NI
160*/
161
162void
164 std::vector<NetDest>& routing_table_entry)
165{
166 NodeID local_src = getLocalNodeID(global_src);
167 assert(local_src < m_nodes);
168
169 GarnetExtLink* garnet_link = safe_cast<GarnetExtLink*>(link);
170
171 // GarnetExtLink is bi-directional
172 NetworkLink* net_link = garnet_link->m_network_links[LinkDirection_In];
173 net_link->setType(EXT_IN_);
174 CreditLink* credit_link = garnet_link->m_credit_links[LinkDirection_In];
175
176 m_networklinks.push_back(net_link);
177 m_creditlinks.push_back(credit_link);
178
179 PortDirection dst_inport_dirn = "Local";
180
182 m_routers[dest]->get_vc_per_vnet());
183
184 /*
185 * We check if a bridge was enabled at any end of the link.
186 * The bridge is enabled if either of clock domain
187 * crossing (CDC) or Serializer-Deserializer(SerDes) unit is
188 * enabled for the link at each end. The bridge encapsulates
189 * the functionality for both CDC and SerDes and is a Consumer
190 * object similiar to a NetworkLink.
191 *
192 * If a bridge was enabled we connect the NI and Routers to
193 * bridge before connecting the link. Example, if an external
194 * bridge is enabled, we would connect:
195 * NI--->NetworkBridge--->GarnetExtLink---->Router
196 */
197 if (garnet_link->extBridgeEn) {
198 DPRINTF(RubyNetwork, "Enable external bridge for %s\n",
199 garnet_link->name());
200 NetworkBridge *n_bridge = garnet_link->extNetBridge[LinkDirection_In];
201 m_nis[local_src]->
202 addOutPort(n_bridge,
203 garnet_link->extCredBridge[LinkDirection_In],
204 dest, m_routers[dest]->get_vc_per_vnet());
205 m_networkbridges.push_back(n_bridge);
206 } else {
207 m_nis[local_src]->addOutPort(net_link, credit_link, dest,
208 m_routers[dest]->get_vc_per_vnet());
209 }
210
211 if (garnet_link->intBridgeEn) {
212 DPRINTF(RubyNetwork, "Enable internal bridge for %s\n",
213 garnet_link->name());
214 NetworkBridge *n_bridge = garnet_link->intNetBridge[LinkDirection_In];
215 m_routers[dest]->
216 addInPort(dst_inport_dirn,
217 n_bridge,
218 garnet_link->intCredBridge[LinkDirection_In]);
219 m_networkbridges.push_back(n_bridge);
220 } else {
221 m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
222 }
223
224}
225
226/*
227 * This function creates a link from the Network to a NI.
228 * It creates a Network Link from a Router to the NI and
229 * a Credit Link from NI to the Router
230*/
231
232void
234 BasicLink* link,
235 std::vector<NetDest>& routing_table_entry)
236{
237 NodeID local_dest = getLocalNodeID(global_dest);
238 assert(local_dest < m_nodes);
239 assert(src < m_routers.size());
240 assert(m_routers[src] != NULL);
241
242 GarnetExtLink* garnet_link = safe_cast<GarnetExtLink*>(link);
243
244 // GarnetExtLink is bi-directional
245 NetworkLink* net_link = garnet_link->m_network_links[LinkDirection_Out];
246 net_link->setType(EXT_OUT_);
247 CreditLink* credit_link = garnet_link->m_credit_links[LinkDirection_Out];
248
249 m_networklinks.push_back(net_link);
250 m_creditlinks.push_back(credit_link);
251
252 PortDirection src_outport_dirn = "Local";
253
255 m_routers[src]->get_vc_per_vnet());
256
257 /*
258 * We check if a bridge was enabled at any end of the link.
259 * The bridge is enabled if either of clock domain
260 * crossing (CDC) or Serializer-Deserializer(SerDes) unit is
261 * enabled for the link at each end. The bridge encapsulates
262 * the functionality for both CDC and SerDes and is a Consumer
263 * object similiar to a NetworkLink.
264 *
265 * If a bridge was enabled we connect the NI and Routers to
266 * bridge before connecting the link. Example, if an external
267 * bridge is enabled, we would connect:
268 * NI<---NetworkBridge<---GarnetExtLink<----Router
269 */
270 if (garnet_link->extBridgeEn) {
271 DPRINTF(RubyNetwork, "Enable external bridge for %s\n",
272 garnet_link->name());
273 NetworkBridge *n_bridge = garnet_link->extNetBridge[LinkDirection_Out];
274 m_nis[local_dest]->
275 addInPort(n_bridge, garnet_link->extCredBridge[LinkDirection_Out]);
276 m_networkbridges.push_back(n_bridge);
277 } else {
278 m_nis[local_dest]->addInPort(net_link, credit_link);
279 }
280
281 if (garnet_link->intBridgeEn) {
282 DPRINTF(RubyNetwork, "Enable internal bridge for %s\n",
283 garnet_link->name());
284 NetworkBridge *n_bridge = garnet_link->intNetBridge[LinkDirection_Out];
285 m_routers[src]->
286 addOutPort(src_outport_dirn,
287 n_bridge,
288 routing_table_entry, link->m_weight,
289 garnet_link->intCredBridge[LinkDirection_Out],
290 m_routers[src]->get_vc_per_vnet());
291 m_networkbridges.push_back(n_bridge);
292 } else {
293 m_routers[src]->
294 addOutPort(src_outport_dirn, net_link,
295 routing_table_entry,
296 link->m_weight, credit_link,
297 m_routers[src]->get_vc_per_vnet());
298 }
299}
300
301/*
302 * This function creates an internal network link between two routers.
303 * It adds both the network link and an opposite credit link.
304*/
305
306void
308 std::vector<NetDest>& routing_table_entry,
309 PortDirection src_outport_dirn,
310 PortDirection dst_inport_dirn)
311{
312 GarnetIntLink* garnet_link = safe_cast<GarnetIntLink*>(link);
313
314 // GarnetIntLink is unidirectional
315 NetworkLink* net_link = garnet_link->m_network_link;
316 net_link->setType(INT_);
317 CreditLink* credit_link = garnet_link->m_credit_link;
318
319 m_networklinks.push_back(net_link);
320 m_creditlinks.push_back(credit_link);
321
323 std::max(m_routers[dest]->get_vc_per_vnet(),
324 m_routers[src]->get_vc_per_vnet()));
325
326 /*
327 * We check if a bridge was enabled at any end of the link.
328 * The bridge is enabled if either of clock domain
329 * crossing (CDC) or Serializer-Deserializer(SerDes) unit is
330 * enabled for the link at each end. The bridge encapsulates
331 * the functionality for both CDC and SerDes and is a Consumer
332 * object similiar to a NetworkLink.
333 *
334 * If a bridge was enabled we connect the NI and Routers to
335 * bridge before connecting the link. Example, if a source
336 * bridge is enabled, we would connect:
337 * Router--->NetworkBridge--->GarnetIntLink---->Router
338 */
339 if (garnet_link->dstBridgeEn) {
340 DPRINTF(RubyNetwork, "Enable destination bridge for %s\n",
341 garnet_link->name());
342 NetworkBridge *n_bridge = garnet_link->dstNetBridge;
343 m_routers[dest]->addInPort(dst_inport_dirn, n_bridge,
344 garnet_link->dstCredBridge);
345 m_networkbridges.push_back(n_bridge);
346 } else {
347 m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
348 }
349
350 if (garnet_link->srcBridgeEn) {
351 DPRINTF(RubyNetwork, "Enable source bridge for %s\n",
352 garnet_link->name());
353 NetworkBridge *n_bridge = garnet_link->srcNetBridge;
354 m_routers[src]->
355 addOutPort(src_outport_dirn, n_bridge,
356 routing_table_entry,
357 link->m_weight, garnet_link->srcCredBridge,
358 m_routers[dest]->get_vc_per_vnet());
359 m_networkbridges.push_back(n_bridge);
360 } else {
361 m_routers[src]->addOutPort(src_outport_dirn, net_link,
362 routing_table_entry,
363 link->m_weight, credit_link,
364 m_routers[dest]->get_vc_per_vnet());
365 }
366}
367
368// Total routers in the network
369int
371{
372 return m_routers.size();
373}
374
375// Get ID of router connected to a NI.
376int
377GarnetNetwork::get_router_id(int global_ni, int vnet)
378{
379 NodeID local_ni = getLocalNodeID(global_ni);
380
381 return m_nis[local_ni]->get_router_id(vnet);
382}
383
384void
386{
388
389 // Packets
392 .name(name() + ".packets_received")
395 ;
396
399 .name(name() + ".packets_injected")
402 ;
403
406 .name(name() + ".packet_network_latency")
408 ;
409
412 .name(name() + ".packet_queueing_latency")
414 ;
415
416 for (int i = 0; i < m_virtual_networks; i++) {
417 m_packets_received.subname(i, csprintf("vnet-%i", i));
418 m_packets_injected.subname(i, csprintf("vnet-%i", i));
421 }
422
424 .name(name() + ".average_packet_vnet_latency")
428
430 .name(name() + ".average_packet_vqueue_latency")
434
436 .name(name() + ".average_packet_network_latency");
439
441 .name(name() + ".average_packet_queueing_latency");
444
446 .name(name() + ".average_packet_latency");
449
450 // Flits
453 .name(name() + ".flits_received")
456 ;
457
460 .name(name() + ".flits_injected")
463 ;
464
467 .name(name() + ".flit_network_latency")
469 ;
470
473 .name(name() + ".flit_queueing_latency")
475 ;
476
477 for (int i = 0; i < m_virtual_networks; i++) {
478 m_flits_received.subname(i, csprintf("vnet-%i", i));
479 m_flits_injected.subname(i, csprintf("vnet-%i", i));
482 }
483
485 .name(name() + ".average_flit_vnet_latency")
488
490 .name(name() + ".average_flit_vqueue_latency")
494
496 .name(name() + ".average_flit_network_latency");
499
501 .name(name() + ".average_flit_queueing_latency");
504
506 .name(name() + ".average_flit_latency");
509
510
511 // Hops
512 m_avg_hops.name(name() + ".average_hops");
514
515 // Links
517 .name(name() + ".ext_in_link_utilization");
519 .name(name() + ".ext_out_link_utilization");
521 .name(name() + ".int_link_utilization");
523 .name(name() + ".avg_link_utilization");
526 .name(name() + ".avg_vc_load")
529 ;
530
531 // Traffic distribution
532 for (int source = 0; source < m_routers.size(); ++source) {
537
538 for (int dest = 0; dest < m_routers.size(); ++dest) {
539 statistics::Scalar *data_packets = new statistics::Scalar();
540 statistics::Scalar *ctrl_packets = new statistics::Scalar();
541
542 data_packets->name(name() + ".data_traffic_distribution." + "n" +
543 std::to_string(source) + "." + "n" + std::to_string(dest));
544 m_data_traffic_distribution[source].push_back(data_packets);
545
546 ctrl_packets->name(name() + ".ctrl_traffic_distribution." + "n" +
547 std::to_string(source) + "." + "n" + std::to_string(dest));
548 m_ctrl_traffic_distribution[source].push_back(ctrl_packets);
549 }
550 }
551}
552
553void
555{
556 RubySystem *rs = params().ruby_system;
557 double time_delta = double(curCycle() - rs->getStartCycle());
558
559 for (int i = 0; i < m_networklinks.size(); i++) {
560 link_type type = m_networklinks[i]->getType();
561 int activity = m_networklinks[i]->getLinkUtilization();
562
563 if (type == EXT_IN_)
565 else if (type == EXT_OUT_)
567 else if (type == INT_)
569
571 (double(activity) / time_delta);
572
573 std::vector<unsigned int> vc_load = m_networklinks[i]->getVcLoad();
574 for (int j = 0; j < vc_load.size(); j++) {
575 m_average_vc_load[j] += ((double)vc_load[j] / time_delta);
576 }
577 }
578
579 // Ask the routers to collate their statistics
580 for (int i = 0; i < m_routers.size(); i++) {
581 m_routers[i]->collateStats();
582 }
583}
584
585void
587{
588 for (int i = 0; i < m_routers.size(); i++) {
589 m_routers[i]->resetStats();
590 }
591 for (int i = 0; i < m_networklinks.size(); i++) {
592 m_networklinks[i]->resetStats();
593 }
594 for (int i = 0; i < m_creditlinks.size(); i++) {
595 m_creditlinks[i]->resetStats();
596 }
597}
598
599void
600GarnetNetwork::print(std::ostream& out) const
601{
602 out << "[GarnetNetwork]";
603}
604
605void
607{
608 int src_node = route.src_router;
609 int dest_node = route.dest_router;
610 int vnet = route.vnet;
611
612 if (m_vnet_type[vnet] == DATA_VNET_)
613 (*m_data_traffic_distribution[src_node][dest_node])++;
614 else
615 (*m_ctrl_traffic_distribution[src_node][dest_node])++;
616}
617
618bool
620{
621 bool read = false;
622 for (unsigned int i = 0; i < m_routers.size(); i++) {
623 if (m_routers[i]->functionalRead(pkt, mask))
624 read = true;
625 }
626
627 for (unsigned int i = 0; i < m_nis.size(); ++i) {
628 if (m_nis[i]->functionalRead(pkt, mask))
629 read = true;
630 }
631
632 for (unsigned int i = 0; i < m_networklinks.size(); ++i) {
634 read = true;
635 }
636
637 for (unsigned int i = 0; i < m_networkbridges.size(); ++i) {
639 read = true;
640 }
641
642 return read;
643}
644
645uint32_t
647{
648 uint32_t num_functional_writes = 0;
649
650 for (unsigned int i = 0; i < m_routers.size(); i++) {
651 num_functional_writes += m_routers[i]->functionalWrite(pkt);
652 }
653
654 for (unsigned int i = 0; i < m_nis.size(); ++i) {
655 num_functional_writes += m_nis[i]->functionalWrite(pkt);
656 }
657
658 for (unsigned int i = 0; i < m_networklinks.size(); ++i) {
659 num_functional_writes += m_networklinks[i]->functionalWrite(pkt);
660 }
661
662 return num_functional_writes;
663}
664
665} // namespace garnet
666} // namespace ruby
667} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
virtual std::string name() const
Definition named.hh:47
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition packet.hh:295
int declare_router(int number_of_inputs, int number_of_outputs, int number_of_vcs_per_vnet, int number_of_buff_per_data_vc, int number_of_buff_per_ctrl_vc)
Topology * m_topology_ptr
Definition Network.hh:158
static uint32_t m_virtual_networks
Definition Network.hh:156
std::vector< std::vector< MessageBuffer * > > m_fromNetQueues
Definition Network.hh:164
NodeID getLocalNodeID(NodeID global_id) const
Definition Network.cc:253
std::vector< std::vector< MessageBuffer * > > m_toNetQueues
Definition Network.hh:163
std::vector< std::string > m_vnet_type_names
Definition Network.hh:157
void createLinks(Network *net)
Definition Topology.cc:115
statistics::Vector m_packet_network_latency
statistics::Formula m_avg_packet_vqueue_latency
void makeInternalLink(SwitchID src, SwitchID dest, BasicLink *link, std::vector< NetDest > &routing_table_entry, PortDirection src_outport_dirn, PortDirection dest_inport_dirn)
std::vector< VNET_type > m_vnet_type
uint32_t functionalWrite(Packet *pkt)
Function for performing a functional write.
void makeExtOutLink(SwitchID src, NodeID dest, BasicLink *link, std::vector< NetDest > &routing_table_entry)
std::vector< std::vector< statistics::Scalar * > > m_data_traffic_distribution
void regStats()
Callback to set stat parameters.
statistics::Scalar m_total_ext_in_link_utilization
int get_router_id(int ni, int vnet)
statistics::Formula m_avg_packet_queueing_latency
statistics::Formula m_avg_flit_queueing_latency
statistics::Vector m_flit_queueing_latency
statistics::Formula m_avg_flit_vqueue_latency
statistics::Scalar m_average_link_utilization
void resetStats()
Callback to reset stats.
statistics::Formula m_avg_flit_network_latency
void init()
init() is called after all C++ SimObjects have been created and all ports are connected.
std::vector< NetworkLink * > m_networklinks
statistics::Vector m_flit_network_latency
std::vector< Router * > m_routers
statistics::Scalar m_total_ext_out_link_utilization
statistics::Scalar m_total_int_link_utilization
statistics::Formula m_avg_packet_network_latency
statistics::Formula m_avg_flit_latency
void update_traffic_distribution(RouteInfo route)
std::vector< std::vector< statistics::Scalar * > > m_ctrl_traffic_distribution
std::vector< CreditLink * > m_creditlinks
statistics::Formula m_avg_packet_latency
void print(std::ostream &out) const
statistics::Formula m_avg_packet_vnet_latency
statistics::Formula m_avg_flit_vnet_latency
bool functionalRead(Packet *pkt, WriteMask &mask)
statistics::Vector m_packet_queueing_latency
void makeExtInLink(NodeID src, SwitchID dest, BasicLink *link, std::vector< NetDest > &routing_table_entry)
std::vector< NetworkInterface * > m_nis
std::vector< NetworkBridge * > m_networkbridges
void printFaultVector(std::ostream &out)
Definition Router.cc:249
void printAggregateFaultProbability(std::ostream &out)
Definition Router.cc:267
void init_net_ptr(GarnetNetwork *net_ptr)
Definition Router.hh:93
uint32_t get_vc_per_vnet()
Definition Router.hh:88
Derived & subname(off_type index, const std::string &name)
Set the subfield name for the given index, and marks this stat to print at the end of simulation.
Derived & name(const std::string &name)
Set the name and marks this stat to print at the end of simulation.
Derived & flags(Flags _flags)
Set the flags and marks this stat to print at the end of simulation.
This is a simple scalar statistic, like a counter.
Derived & init(size_type size)
Set this vector to have the given size.
STL vector class.
Definition stl.hh:37
const Params & params() const
virtual void init()
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition sim_object.cc:73
virtual void regStats()
Callback to set stat parameters.
Definition group.cc:68
#define inform(...)
Definition logging.hh:257
Bitfield< 3, 0 > mask
Definition pcstate.hh:63
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 9, 8 > rs
Bitfield< 0 > p
Bitfield< 3 > ni
Definition misc.hh:104
Bitfield< 18 > sum
Definition misc.hh:1198
unsigned int SwitchID
std::string PortDirection
unsigned int NodeID
const FlagsType pdf
Print the percent of the total that this entry represents.
Definition info.hh:61
const FlagsType oneline
Print all values on a single line.
Definition info.hh:71
const FlagsType nozero
Don't print if this is zero.
Definition info.hh:67
const FlagsType total
Print the total.
Definition info.hh:59
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
T safe_cast(U &&ref_or_ptr)
Definition cast.hh:74
std::string csprintf(const char *format, const Args &...args)
Definition cprintf.hh:161

Generated on Tue Jun 18 2024 16:24:05 for gem5 by doxygen 1.11.0